组合继承通过构造函数继承+原型链继承解决原型链缺陷:第一步在子构造函数中调用Parent.call(this)实现传参和引用属性独立,第二步用Object.create(Parent.prototype)继承方法并修正constructor。

组合继承通过“构造函数继承 + 原型链继承”双管齐下,既让每个实例拥有独立的引用属性(如数组、对象),又支持创建子类实例时向父类传参,还能复用父类方法——它不是折中方案,而是针对原型链固有缺陷的精准修复。
为什么原型链单独用会出问题
直接让 Child.prototype = new Parent(),会导致两个硬伤:
- 父类构造函数在设置原型时就被执行一次,其中的
this.colors = ['red']成为所有子实例共用的引用地址 - 那次执行无法接收子类实例化时传的参数(比如
new Child('Alice', 12)),父类的name和age只能写死或留空
组合继承的两步关键动作
它把“初始化数据”和“连接方法”拆开处理,各司其职:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
第一步:在子构造函数里调用
Parent.call(this, name, age)
每次new Child()都会执行一次父类构造逻辑,this指向新实例,所以this.friends = []每次都新建数组,彻底隔离 -
第二步:用
Object.create(Parent.prototype)设置子原型
不执行父构造函数,只继承父类原型上的方法(如sayName),避免污染;再手动修正constructor指针
传参和独立引用怎么同时实现
核心在于:参数只在第一步生效,而引用属性的独立性也由第一步保障。例如:
立即学习“Java免费学习笔记(深入)”;
function Animal(name, legs) {
this.name = name; // 基础值类型,自然独立
this.tags = []; // 引用类型,在此处初始化 → 每个实例一份
this.legs = legs;
}
Animal.prototype.move = function() { return 'moving'; };
function Dog(name, legs, breed) {
// ✅ 这里传参,且确保 tags 等引用属性不共享
Animal.call(this, name, legs);
this.breed = breed;
}
// ✅ 这里只继承方法,不触发 Animal 构造函数
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
const d1 = new Dog('Leo', 4, 'Golden');
const d2 = new Dog('Max', 4, 'Husky');
d1.tags.push('pet');
console.log(d2.tags); // [] —— 完全不受影响
注意避开两个典型坑
- 别写
Dog.prototype = new Animal():这又回到了原型链的老路,tags会挂到原型上被共享 - 别漏掉
Dog.prototype.constructor = Dog:否则new Dog() instanceof Animal虽为 true,但instance.constructor会错误指向Animal

















