借用构造函数继承能避免引用类型属性共享,因为每次创建子类实例时都通过call/appl调用父类构造函数,为每个实例独立初始化属性;而原型链继承会使引用属性挂载在原型上被所有实例共享。

JavaScript中借用构造函数继承(也叫经典继承)能有效避免原型链继承时引用类型属性被所有实例共享的问题。
为什么原型链继承会导致引用属性共享
当通过原型链实现继承时,父类的引用类型属性(如数组、对象)会被所有子类实例共用。因为它们实际存储在原型对象上,修改其中一个实例的该属性,会影响其他实例。
例如:
function Parent() {this.colors = ['red', 'blue'];
}
function Child() {}
Child.prototype = new Parent(); // 原型继承
const c1 = new Child();
const c2 = new Child();
c1.colors.push('green');
console.log(c2.colors); // ['red', 'blue', 'green'] ← 被意外修改了
借用构造函数继承的核心做法
在子类构造函数内部,用 call 或 apply 调用父类构造函数,让父类中的 this 指向当前子类实例。这样每次创建子类实例时,都会执行父类构造函数逻辑,为每个实例独立初始化引用属性。
- 父类中的实例属性(包括引用类型)不再挂载在原型上,而是直接添加到每个子类实例自身
- 子类实例之间互不影响,彻底解决共享问题
- 可向父类构造函数传参,支持个性化初始化
典型实现方式与注意事项
常见写法:
function Parent(name) {this.name = name;
this.colors = ['red', 'blue'];
}
function Child(name, age) {
// 借用父类构造函数,为当前实例初始化属性
Parent.call(this, name);
this.age = age;
}
const c1 = new Child('Alice', 20);
const c2 = new Child('Bob', 25);
c1.colors.push('green');
console.log(c2.colors); // ['red', 'blue'] ← 不受影响
注意点:
- 只继承实例属性,不继承原型上的方法——子类无法复用父类原型方法,需额外处理(如组合继承或寄生组合继承)
- 每次创建子类实例都会调用一次父类构造函数,可能存在性能开销(但通常可忽略)
- 父类原型链上的属性和方法不会被继承,若需方法复用,应配合原型链使用
更实用的组合方案:寄生组合继承
为兼顾属性隔离与方法复用,现代常用“寄生组合继承”:用借用构造函数继承属性,用原型链继承方法。
- 先用 Object.create(Parent.prototype) 创建干净的原型对象,避免调用父类构造函数
- 将该对象赋给 Child.prototype
- 在 Child 构造函数中用 Parent.call(this, ...) 继承实例属性
这是目前最推荐的继承模式,既避免引用共享,又不重复执行父类构造函数,还支持方法复用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











