原型链导致引用属性共享,因子类原型是父类实例,引用值挂载在原型上;借用构造函数通过Super.call(this)使每个实例拥有独立引用副本;组合继承兼顾二者优势。

原型链本身不能解决引用类型共享问题,反而正是这个问题的根源;真正起作用的是“借用构造函数”——它绕开原型链,在每次实例化时独立执行父类构造逻辑,从而让每个实例拥有自己的一份引用属性副本。
为什么原型链会导致引用属性被共享
当用 Sub.prototype = new Super() 建立继承关系时,子类原型是父类的一个实例。如果父类构造函数里写了 this.items = [] 或 this.config = {},这个数组或对象就挂在了原型对象上。所有子类实例通过原型链访问到的,都是同一个内存地址里的引用值。
结果就是:修改 instanceA.items.push(1),instanceB.items 也会多出一个 1。
借用构造函数怎么切断共享链
它不依赖原型,而是在子类构造函数内部,用 call 或 apply 把父类构造函数“拉进来”,并把 this 绑定到当前正在创建的新实例上:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 每次 new Sub(),都会执行一次 Super.call(this)
- 父类构造函数中的 this.xxx = [...] 就直接赋值给了子类实例自身,不是挂到原型上
- 每个实例都拥有独立的 colors、handlers 等属性,互不影响
它和原型链不是对立关系,而是分工配合
单独用借用构造函数,会丢失父类原型上的方法(比如 Super.prototype.sayName),也破坏 instanceof 判断。所以实际中常采用“组合继承”:
- 在子类构造函数里用 Super.call(this, ...) 继承实例属性(尤其是数组、对象等引用类型)
- 用 Sub.prototype = Object.create(Super.prototype) 建立原型链,复用父类方法
- 手动修复 Sub.prototype.constructor = Sub,避免 constructor 指向错误
一个典型组合继承示例
function Super(name) {
this.name = name;
this.favorites = ['music'];
}
Super.prototype.greet = function() { return 'Hi, ' + this.name; };
function Sub(name, age) {
Super.call(this, name); // ✅ 每个实例都有自己的 favorites 数组
this.age = age;
}
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
const a = new Sub('Alice', 25);
const b = new Sub('Bob', 30);
a.favorites.push('coding');
console.log(b.favorites); // ['music'] —— 不受影响
console.log(a.greet()); // 'Hi, Alice' —— 方法也能正常调用

















