寄生组合式继承是目前最被推荐的js继承方式:父类构造函数只执行一次、方法复用不浪费内存、支持传参、instanceof正常;缺点是写法繁琐、需手动修复constructor、初学者不友好、小型项目易过度设计。

寄生组合式继承是 JavaScript 中最理想的继承方式,它只调用一次父类构造函数,同时又能复用父类原型上的方法,避免了组合式继承中父类构造函数被调用两次的问题。
核心思想:用 Object.create 搭建干净的原型链
关键在于不直接用 new Parent() 去创建子类原型,而是用 Object.create(Parent.prototype) 创建一个仅继承自父类原型的新对象。这样既保留了父类原型的方法,又不会执行父类构造逻辑(比如初始化实例属性)。
- 子类构造函数内部仍用 Parent.call(this, ...) 继承实例属性
- 子类原型则通过 Object.create(Parent.prototype) 获取父类原型方法
- 最后补上 constructor 指向,避免丢失子类构造器引用
标准实现代码(可直接复用)
下面是一个通用、健壮的寄生组合式继承封装:
function inheritPrototype(SubType, SuperType) {
const prototype = Object.create(SuperType.prototype);
prototype.constructor = SubType;
SubType.prototype = prototype;
}
// 使用示例
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function() {
console.log(this.name);
};
function Dog(name, breed) {
Animal.call(this, name); // 继承实例属性
this.breed = breed;
}
inheritPrototype(Dog, Animal); // 继承原型方法
Dog.prototype.bark = function() {
console.log('Woof!');
};
为什么比其他方式更优?
对比常见继承模式:
- 原型链继承:无法传参给父类构造函数,且所有实例共享引用类型属性
- 借用构造函数:无法复用父类原型方法,每次创建实例都重复定义方法
- 组合式继承:父类构造函数被调用两次(一次在设置原型时,一次在子类构造内),造成冗余初始化
- 寄生组合式继承:只调用一次父类构造函数,原型链干净,语义清晰,ES5 环境下最推荐
ES6 class 是怎么处理的?
ES6 的 class extends 在底层正是基于寄生组合式继承的思想实现的(Babel 编译后就能看到类似 Object.create 和 call 的组合)。所以写 class Dog extends Animal 本质上就是语法糖,背后仍是这套机制。
不复杂但容易忽略细节,重点是理解 谁负责实例属性,谁负责原型方法,以及如何切断不必要的构造调用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











