JS类与继承
一些概念
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教程;