JS类与继承

作者: Quilljou | 来源:发表于2017-07-20 10:25 被阅读59次

    一些概念

    prototype是构造函数的指针,指向原型对象。讲述的是构造函数和原型对象之间的关系。
    __proto__是实例对象的指针,也指向原型对象,讲述的是实例对象和原型对象之间的关系。
    因为原型对象也是对象,所以原型对象也有__proto__,指向的是这个原型对象的原型对象,JS实现继承的方式就是根据__proto__指针,在一个对象上查找一个property,会依次在自身对象、原型对象、原型对象的原型对象(就是原型链)。
    所以在js中实现继承的关键就是使得一个原型对象的__proto__指针指向某一个(原型)对象。

    最后在说一下constructor指针。
    constructor是原型对象的的指针,指向构造函数。讲述的是原型对象和构造函数之间的关系。所以和prototype是互逆的一对指针。

    《《JavaScript高级程序设计》》第三版讲解原型和继承对于有些基础的人有些拖沓。其中第六章第三节讲解继承的时候也告诉了在JavaScript实现继承的业界默认方式就是借用构造函数和原型继承。

    其背后的思路就是使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承。

    上面这句话总结的很好很全面了。

    所以继承包括两个方面,实例属性和原型属性的继承。

    继承实例属性最常用的一种方法是上面说到的借用构造函数。

    function ParentClass() { // 父类构造函数
    }
    
    function ChildrenClass(xx,yy,zz) { // 子类构造函数
      ParentClass.call(this,xx,yy);
      this.zz = zz;
    }
    

    继承原型属性的方法就有很多种了。

    Object.create

    function inherit(C,P) {
      C.prototype = Object.create(P.prototype)
    }
    
    inherit(ChildrenClass,ParentClass)
    

    最早老道提出来这种方法叫原型式继承。实现了一个create方法,只不过ES5在语法层面实现了create方法,形成了上面的方法。

    function create(o) {
      var F = new Function();
      F.prototype = o;
      return new F();
    }
    
    function inherit(C,P) {
      C.prototype = create(P.prototype)
    }
    
    inherit(ChildrenClass,ParentClass)
    

    原型式继承之二

    function inherit(C,P) {
        var F = new Function();  // 临时构造函数
        F.prototype = P.prototype;
        C.super = P; // 使得子类能够获得对父类的引用
        C.prototype = new F(); // 使得子类的原型对象__proto__指向父类的原型对象,从而实现继承原型方法
        C.prototype.constructor = C; // 使得子类的constructor指针重新指向子类的构造函数
    }
    
    inherit(ChildrenClass,ParentClass)
    

    setPrototypeOf

    const inherit = function(ctor, superCtor) {
    
      if (ctor === undefined || ctor === null)
        throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'ctor', 'function');
    
      if (superCtor === undefined || superCtor === null)
        throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'superCtor', 'function');
    
      if (superCtor.prototype === undefined) {
        throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'superCtor.prototype',
                                   'function');
      }
      ctor.super_ = superCtor;
      Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
    };
    

    上面一段代码来自node的util模块的inherits方法。使用了ES6的Object.setPrototypeOf.
    其实都ES6了,为什么不直接使用ES6的extends关键字。

    ES6

    ES6的到来,为JS实现了语言层面的class。其实也只是上面内容的一个语法糖。即使在各种环境都支持ES6和class的情况下,熟悉和了解JS中继承是如何实现的也是很有必要的。
    详细的ES6 class讲解可以参考 阮一峰的ES6教程;

    相关文章

      网友评论

        本文标题:JS类与继承

        本文链接:https://www.haomeiwen.com/subject/gwddkxtx.html