借用构造函数继承通过parent.call(this, name)为每个子类实例独立执行父类构造逻辑,使引用属性(如colors)生成独立副本,避免原型链继承中因共享同一父类实例而导致的修改污染;但无法继承父类原型方法,需配合原型链实现组合继承。

借用构造函数继承通过在子类构造函数中用 call() 或 apply() 调用父类构造函数,让父类的属性(包括引用类型)在每个子类实例内部重新初始化,从而避免共享。
为什么引用属性会共享?
原型链继承时,子类原型是父类的一个实例:
所有子类实例的 __proto__ 都指向同一个父类实例对象。
如果这个父类实例里有数组、对象等引用类型属性(如 this.colors = ['red']),那它们就被所有子类实例共用——改一个,全跟着变。
借用构造函数怎么切断共享?
它不依赖原型共享,而是把父类构造函数当成普通函数来执行,并显式绑定 this 到当前子类实例上:
- 每次创建子类实例时,Parent.call(this, ...) 都会为该实例单独执行一遍父类构造逻辑
- 父类中定义的 this.colors = [...] 就会在每个子类实例上生成一份独立副本
- 修改 child1.colors.push(...) 不会影响 child2.colors
实际写法示例
✅ 正确做法:
function Parent(name) {
this.name = name;
this.colors = ['red', 'blue'];
}
function Child(name, age) {
Parent.call(this, name); // 关键:为每个 child 实例独立执行一次 Parent 初始化
this.age = age;
}
const child1 = new Child('Alice', 25);
const child2 = new Child('Bob', 30);
child1.colors.push('green');
console.log(child1.colors); // ['red', 'blue', 'green']
console.log(child2.colors); // ['red', 'blue'] ← 完全不受影响
注意它的局限性
这种方式只解决了属性隔离问题,但带来新限制:
- 父类定义在 prototype 上的方法(如 Parent.prototype.sayName)无法被继承
- 所有方法都得写在构造函数里,导致每次实例化都新建一份,浪费内存
- 所以它通常要和原型链继承配合使用,也就是组合继承
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











