借用构造函数是通过在子类构造函数中用Parent.call(this, ...args)调用父类构造函数,使每个实例独享属性;它解决原型上引用类型被共享的问题,但不继承原型方法,需额外处理。

借用构造函数(Constructor Borrowing)是 JavaScript 中实现“实例属性独占”的核心手段,尤其用于解决原型上引用类型属性被多个实例共享的问题。它的本质是在子类构造函数中,用 call 或 apply 显式调用父类构造函数,并将 this 绑定到当前子类实例上,从而让父类内部的 this.xxx = xxx 逻辑为每个实例独立执行一次。
为什么需要借用构造函数?
直接使用原型继承时,若把数组、对象等引用类型属性写在父类原型上,所有子实例会共享同一份内存地址——改一个,全跟着变。而借用构造函数把初始化逻辑“拉进实例”,确保每个对象都有自己的副本。
- 原型上的
colors = ['red']→ 所有实例共用一个数组 - 构造函数内
this.colors = ['red']→ 每个实例新建一个数组
怎么写:标准借用模式
在子类构造函数第一行,用 Parent.call(this, ...args) 调用父类构造逻辑:
- 必须传入 this,否则父类内部的 this 会指向错误上下文
- 后续参数按父类构造函数签名依次传入(如
name,id等) - 父类内部对 this 的赋值(
this.name = name、this.items = [])全部作用于当前子实例
示例:
立即学习“Java免费学习笔记(深入)”;
function Animal(name) {
this.name = name;
this.hobbies = ['sleep', 'eat']; // 引用类型,在实例上初始化
}
function Dog(name, breed) {
Animal.call(this, name); // ✅ 借用:每个 Dog 实例都获得独立的 name 和 hobbies
this.breed = breed;
}
const d1 = new Dog('Leo', 'Golden');
const d2 = new Dog('Max', 'Husky');
d1.hobbies.push('bark');
console.log(d2.hobbies); // ['sleep', 'eat'] —— 不受影响
和 class + super() 的区别
ES6 class 中的 super() 本质也是借用构造函数的一种封装,但它强制要求语法合规:
- 子类写了
constructor就必须首行调用super() - 不调用会报
ReferenceError: Must call super constructor... - 而传统函数方式更灵活,可条件调用、多次调用、甚至借用多个父类(如多重继承模拟)
注意事项
- 只借用构造函数,不继承原型方法——需额外用
Object.setPrototypeOf(Dog.prototype, Animal.prototype)或组合式继承补全 - 不能替代
new:仍需用new Dog()创建实例,否则this会丢失 - 避免重复初始化:如果父类构造函数含副作用(如发请求、改全局状态),多次借用要小心


















