寄生组合式继承通过object.create(super.prototype)创建空对象并修正constructor,使子类原型直接继承父类原型方法,避免父类构造函数被调用两次;es6的class extends是其语法糖。

寄生组合式继承通过只调用一次父类构造函数,同时保留原型链继承关系,从根本上解决经典组合继承中父类构造函数被调用两次的问题。
问题根源:经典组合继承为什么调用两次?
经典组合继承写法如下:
function Super() {
this.name = 'super';
}
Super.prototype.say = function() { return this.name; };
function Sub() {
Super.call(this); // 第一次调用
}
Sub.prototype = new Super(); // 第二次调用(创建新实例时执行 Super())
问题出在 Sub.prototype = new Super() 这一步:为了继承父类原型方法,不得不 new 一个父类实例,导致父类构造函数再次执行,且该实例上的属性(如 name)会冗余地挂载在原型上,既浪费内存又逻辑混乱。
核心思路:不 new 父类,只复用其原型
寄生组合式继承的关键是绕过 new Super(),改用一个中间函数“桥接”原型,让子类原型干净地指向父类原型对象,而不是父类实例:
- 用
Object.create(Super.prototype)创建一个空对象,其__proto__直接指向Super.prototype - 这样既继承了父类所有原型方法,又完全避免执行父类构造函数
- 再把子类原型的
constructor指回自身,保持语义正确
标准实现:封装一个 inherit 函数
通常将复用逻辑封装成工具函数,便于复用:
function inherit(Child, Parent) {
const prototype = Object.create(Parent.prototype);
prototype.constructor = Child;
Child.prototype = prototype;
}
// 使用示例
function Super(name) {
this.name = name;
}
Super.prototype.say = function() { return this.name; };
function Sub(name, age) {
Super.call(this, name); // 只在此处调用一次
this.age = age;
}
inherit(Sub, Super); // 不触发 Super 构造函数
const s = new Sub('Alice', 25);
console.log(s.say()); // 'Alice'
console.log(s instanceof Sub); // true
console.log(s instanceof Super); // true
此时 Sub.prototype 是一个纯净对象,没有 name 属性,只有从 Super.prototype 继承来的方法,彻底规避重复初始化。
现代替代方案:class + extends(推荐)
ES6 的 class 和 extends 语法底层就是寄生组合式继承的语法糖:
class Super {
constructor(name) {
this.name = name;
}
say() { return this.name; }
}
class Sub extends Super {
constructor(name, age) {
super(name); // 父类构造仅调用一次
this.age = age;
}
}
Babel 或现代引擎编译后,实际生成的代码正是上述 Object.create + call 的组合。日常开发中直接使用 extends 即可,语义清晰、安全可靠。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











