继承的方式5(最推荐):组合继承的优化2(寄生组合继承)
面试速答(30 秒版 TL;DR)
- 目标:同时做到:
- 继承实例属性:
Parent.call(this, ...) - 继承原型方法:让
Child.prototype的原型指向Parent.prototype - 不调用
Parent构造函数去“生成原型对象”
- 继承实例属性:
- 推荐写法:
Child.prototype = Object.create(Parent.prototype)Child.prototype.constructor = Child- 可选:
Object.setPrototypeOf(Child, Parent)让子类也继承父类的静态属性/方法
图示:子类原型“委托”给父类原型,但不是同一个对象
最小可运行示例(推荐)
function Parent(name) {
this.name = name;
this.tags = [];
}
Parent.prototype.say = function () {
return `I am ${this.name}`;
};
Parent.staticFn = function () {
return "static";
};
function Child(name) {
Parent.call(this, name); // 继承实例属性
}
// 继承原型方法(不执行 Parent 构造函数)
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
// 可选:继承静态方法(类本身的原型链)
Object.setPrototypeOf(Child, Parent);
const c = new Child("alice");
console.log(c.say()); // "I am alice"
console.log(Child.staticFn()); // "static"
为什么这才是“最推荐”的 ES5 时代写法?
- 不会把父类构造函数里的实例字段“挂到
Child.prototype上”,避免共享引用类型属性。 - 不会额外执行一次父构造函数,减少副作用和性能浪费。
- 父类原型方法只保留一份,实现真正的复用。
易错点/坑
- 别忘了修正
constructor:Child.prototype.constructor = Child。 Object.setPrototypeOf可能有性能成本,通常只在需要继承静态方法时再加;否则可以不写。
速记要点(可背诵)
- 寄生组合继承 =
Parent.call(this)+Child.prototype = Object.create(Parent.prototype)。 - 不二次调用父构造函数,也不共享同一个原型对象。