寄生组合继承通过空函数中介避免父类构造函数冗余调用,仅执行一次Parent.call(this)初始化实例属性,使原型链继承干净、安全且语义清晰。

寄生组合继承通过“一次调用父类构造函数 + 安全复用原型方法”的方式,精准解决了组合继承中父类构造函数被调用两次的性能缺陷。
核心问题:组合继承为什么浪费性能?
组合继承执行了两次父类构造函数:
- 第一次在子类构造函数内:Parent.call(this, ...) —— 为子类实例初始化独有属性(必要且合理)
- 第二次在设置原型时:Child.prototype = new Parent() —— 仅为获取父类原型链,却意外触发完整构造逻辑(如初始化 DOM、发请求、创建冗余属性等)
这不仅多执行一次无意义的初始化,还导致子类原型上存在一份被遮蔽的父类实例属性(如 this.name),白白占用内存。
寄生组合继承怎么做?关键就一个空函数
它用一个不带逻辑的中介函数切断“原型赋值即执行构造函数”的耦合:
- 定义空函数 F = function() {}
- 让 F.prototype = Parent.prototype(只关联原型,不执行 Parent)
- 再用 new F() 创建干净的原型对象 —— 它的
__proto__指向Parent.prototype,但自身无实例属性 - 最后将 Child.prototype = new F(),并修复
constructor
这样,子类原型链完整继承了父类方法,又完全规避了多余构造函数调用。
代码对比更直观
组合继承(两次调用):
Cat.prototype = new Animal(); // ❌ 这里又执行了一次 Animal 构造函数寄生组合继承(零次冗余调用):
function F() {}F.prototype = Animal.prototype;
Cat.prototype = new F(); // ✅ 只创建空壳,不触发 Animal 执行
真正执行父类构造逻辑的,仅保留在 Animal.call(this, ...) 那一次——既支持传参,又无副作用。
它不只是省一次调用,还带来三个隐性收益
- 子类原型干净:没有被废弃的父类实例属性(如
name、colors),避免属性查找干扰 - 初始化安全:父类若含副作用操作(如
fetch()、document.createElement),不会在原型设置阶段意外触发 - 语义清晰:构造函数负责“实例状态”,原型链负责“行为共享”,职责彻底分离











