组合继承的工作方式
- 原型链继承:通过将子类的原型指向父类的实例,实现子类对父类原型属性和方法的继承。例如:
function Parent() {
this.value = 1;
}
Parent.prototype.getValue = function() {
return this.value;
};
function Child() {
this.childValue = 2;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
- 借用构造函数继承:在子类构造函数内部调用父类构造函数,实现子类对父类实例属性的继承。例如:
function Child() {
Parent.call(this);
this.childValue = 2;
}
优点
- 既继承了原型上的方法:保证了函数复用,多个实例共享父类原型上的方法,节省内存。
- 又继承了实例属性:每个子类实例都有自己独立的属性,互不干扰。
缺点
- 父类构造函数被调用两次:一次是在
Child.prototype = new Parent();
创建子类原型时,另一次是在 Parent.call(this);
子类构造函数内部。这导致了不必要的性能开销,父类实例属性会在子类原型和子类实例上各创建一份。
改进思路
- 寄生组合继承:不通过
new Parent()
创建子类原型,而是通过创建一个临时构造函数,将其原型指向父类原型,然后将子类原型指向这个临时构造函数的实例。这样既避免了父类构造函数的重复调用,又能正确建立原型链。
关键代码片段
function Parent() {
this.value = 1;
}
Parent.prototype.getValue = function() {
return this.value;
};
function Child() {
Parent.call(this);
this.childValue = 2;
}
// 寄生组合继承核心代码
function inheritPrototype(subType, superType) {
let prototype = Object.create(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
inheritPrototype(Child, Parent);