寄生组合式继承通过object.create(parent.prototype)替代new parent()建立原型链,使父类构造函数仅在子类实例化时被调用一次,避免了组合继承中二次调用的性能开销与引用属性共享问题。

组合寄生式继承在构造开销上的精简,核心在于只调用一次父类构造函数,避免了传统组合继承中父类构造函数被重复执行的问题,同时彻底绕开了原型链继承中因共享原型实例带来的属性污染与冗余初始化。
传统原型链继承的构造开销问题
原型链继承直接让子类原型等于父类实例:Sub.prototype = new Super()。这会导致:
- 每次设置子类原型时,都必须执行一次 Super() 构造函数;
- 若父类构造函数中有耗时逻辑(如初始化大型数组、发起同步计算、读取配置等),该操作会在原型赋值阶段无意义地执行;
- 更关键的是,父类实例中的引用类型属性(如 this.items = [])会被所有子类实例共享,后续修改会相互影响;
- 子类实例无法拥有独立的实例属性副本,只能依赖原型查找,丧失封装性。
传统组合继承为何多调用一次
组合继承尝试兼顾属性与方法继承,写法是:
- 在子类构造函数内调用
Super.call(this, ...)—— 第一次调用父类构造函数,用于初始化当前实例的自有属性; - 又通过
Sub.prototype = new Super()设置原型 —— 第二次调用父类构造函数,只为把方法挂到原型上,却顺带又创建了一套无用的实例属性(如重复的colors数组)。
这两次调用中,第二次纯属“为借方法而硬造实例”,造成内存浪费和逻辑冗余。
寄生组合式继承如何切断冗余调用
它用一个轻量中介函数替代 new Super() 来承接原型链,关键三步:
- 定义空函数
F,仅作桥梁; - 让
F.prototype = Super.prototype,不触发Super执行; - 再让
Sub.prototype = new F(),此时F是空构造函数,实例化零开销,且新对象的__proto__直接指向Super.prototype。
这样一来,父类构造函数仅在子类实例化时由 Super.call(this) 调用一次,专用于初始化当前实例;原型链上的方法继承完全脱离父类构造逻辑,干净、高效、可预测。
实际效果对比
假设父类有:
function Animal(name) {
console.log('Animal 构造函数执行');
this.name = name;
this.skills = ['run', 'jump'];
}
使用寄生组合继承后:
- 创建子类原型时,console.log 不会触发;
- 每个子类实例(如 new Dog('旺财'))才执行一次构造日志;
- skills 是实例自有属性,彼此隔离;
- 方法(如 Animal.prototype.eat)仍可通过原型链访问,不丢失复用性。










