寄生组合式继承通过Object.create(Super.prototype)替代new Super(),使父类构造函数仅调用一次,避免属性冗余和引用共享;再修正constructor指向,完整保留实例属性隔离与原型方法复用。

寄生组合式继承是目前 ES5 环境下最推荐的继承方案,它解决了经典组合继承中父类构造函数被调用两次的核心缺陷,同时完整保留了实例属性隔离和原型方法复用两大优势。
为什么需要寄生组合式继承
经典组合继承写法如下:
function Super(name) { this.name = name; this.colors = ['red']; }
Super.prototype.say = function() { return this.name; };
function Sub(name, age) { Super.call(this, name); this.age = age; }
Sub.prototype = new Super(); // 问题就在这里:执行了一次 Super()
Sub.prototype.constructor = Sub;
这会导致两个问题:
- 父类构造函数被执行两次:一次在 Sub.prototype = new Super(),另一次在 Super.call(this, name)
- 第一次执行产生的实例属性(如
colors)被挂到Sub.prototype上,造成冗余且易引发引用类型共享问题
核心实现逻辑:绕过 new,只复用原型
关键在于不通过 new Super() 创建原型对象,而是用 Object.create(Super.prototype) 直接以父类原型为原型创建一个干净空对象:
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- 该空对象的
__proto__指向Super.prototype,因此能访问所有父类原型方法 - 父类构造函数完全不执行,避免属性重复创建和副作用
- 再手动修正
constructor指针,保持语义正确
标准封装写法(可复用工具函数)
function inheritPrototype(Child, Parent) {
const proto = Object.create(Parent.prototype);
proto.constructor = Child;
Child.prototype = proto;
}
使用时只需替换掉原来有问题的原型赋值语句:
- 把
Sub.prototype = new Super();改为inheritPrototype(Sub, Super); - 子类构造函数内仍保留
Super.call(this, name)继承实例属性 - 后续可在
Sub.prototype上安全添加子类特有方法
ES6 class 是它的语法糖
ES6 的 class A extends B 在底层正是基于寄生组合式继承思想实现的:
- 自动调用
Object.setPrototypeOf(Sub.prototype, Super.prototype)(等价于Object.create(Super.prototype)) - 自动处理
constructor指向 - 子类构造器中必须显式调用
super(),对应Super.call(this, ...)
所以理解寄生组合式继承,就是理解 ES6 继承的底层骨架。

















