组合继承是JavaScript中最常用继承模式,通过构造函数继承父类实例属性(解决共享与传参问题)和原型链继承父类原型方法(实现复用),并需修正constructor指向。

组合继承是 JavaScript 中最常用、最推荐的继承方式之一,它结合了构造函数继承(解决属性独有性)和原型链继承(解决方法复用),既保证了每个实例拥有独立的属性,又让方法能被所有实例共享。
核心思路:先用 call 继承父类实例属性,再用 prototype 链接父类原型方法
关键在于两步不重叠、不遗漏:
- 在子类构造函数中,用 Parent.call(this, ...args) 把父类的实例属性(如 this.name、this.age)复制一份给当前子实例;
- 把子类的 prototype 指向一个父类的实例(new Parent()),这样子类原型上就拥有了父类原型上的所有方法;
- 别忘了修正子类 constructor,否则
Child.prototype.constructor会指向 Parent。
标准写法(带 constructor 修复)
以下是一个完整可运行的例子:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
function Animal(name, age) {
this.name = name;
this.age = age;
}
Animal.prototype.eat = function() {
console.log(this.name + ' is eating');
};
function Dog(name, age, breed) {
// ✅ 第一步:构造函数继承(获取实例属性)
Animal.call(this, name, age);
this.breed = breed; // 子类自有属性
}
// ✅ 第二步:原型链继承(复用父类方法)
Dog.prototype = new Animal(); // 创建父类实例作为子类原型
Dog.prototype.constructor = Dog; // ? 修复 constructor 指向
// ✅ 子类扩展方法
Dog.prototype.bark = function() {
console.log(this.name + ' is barking');
};
// 使用
const dog1 = new Dog('Xiaohei', 3, 'Labrador');
const dog2 = new Dog('Wangcai', 2, 'Poodle');
console.log(dog1.name); // Xiaohei
console.log(dog1.breed); // Labrador
dog1.eat(); // Xiaohei is eating (来自 Animal.prototype)
dog1.bark(); // Xiaohei is barking (子类自有方法)
为什么不用 Object.create(Animal.prototype)?
用 Object.create(Animal.prototype) 是寄生组合式继承更优解,但严格来说它不属于“组合继承”,而是它的优化版。原生组合继承的定义就是:构造函数继承 + new Parent() 设置原型。虽然 new Parent() 会执行一次父构造函数(可能有副作用或冗余初始化),但它简单直接、语义清晰,适合大多数场景。
常见坑点提醒
-
忘记修复 constructor:会导致
dog1.constructor === Animal,影响 instanceof 判断和反射操作; -
在设置 prototype 前就添加子类方法:比如把
Dog.prototype.bark = ...写在Dog.prototype = new Animal()之前,这些方法会被覆盖丢失; -
父类构造函数有副作用:例如发请求、改全局状态,用
new Animal()设置原型时会被执行一次——这时建议改用寄生组合式继承。
组合继承不是最精简的方案,但它是平衡性最好、最容易理解、出错率最低的继承模式,适合日常开发和教学使用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










