让前端飞WEB前端程序开发

JS类与继承

2017-07-20  本文已影响59人  Quilljou

一些概念

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教程;

上一篇下一篇

猜你喜欢

热点阅读