跳到主要内容

继承的方式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 上”,避免共享引用类型属性。
  • 不会额外执行一次父构造函数,减少副作用和性能浪费。
  • 父类原型方法只保留一份,实现真正的复用。

易错点/坑

  • 别忘了修正 constructorChild.prototype.constructor = Child
  • Object.setPrototypeOf 可能有性能成本,通常只在需要继承静态方法时再加;否则可以不写。

速记要点(可背诵)

  • 寄生组合继承 = Parent.call(this) + Child.prototype = Object.create(Parent.prototype)
  • 不二次调用父构造函数,也不共享同一个原型对象。