构造函数继承通过call/apply实现属性独立,确保每个实例拥有自身属性副本;es6 class中super()自动完成此操作,更安全简洁。

构造函数继承要实现属性独立,核心是让每个实例拥有自己的一份属性副本,而不是共享原型上的引用类型数据。关键在于:在子构造函数中调用父构造函数时,使用 call 或 apply 改变 this 指向,把父构造函数中的属性“注入”到当前实例上。
用 call 绑定 this,初始化实例自有属性
这是最直接的方式。父构造函数中定义的属性(尤其是基本类型和新创建的引用类型)会在每次调用时重新生成,确保彼此隔离。
function Parent(name, hobbies) {
this.name = name;
this.hobbies = hobbies || []; // 每次新建数组,不共用
}
function Child(name, hobbies, grade) {
// 关键:用 call 把 Parent 的属性挂到 this 上
Parent.call(this, name, hobbies);
this.grade = grade; // 子类自有属性
}
const c1 = new Child('小明', ['读书', '游泳'], 95);
const c2 = new Child('小红', ['画画'], 98);
console.log(c1.hobbies); // ['读书', '游泳']
console.log(c2.hobbies); // ['画画']
c1.hobbies.push('跑步');
console.log(c2.hobbies); // ['画画'] —— 不受影响
避免在原型上定义可变对象
如果把数组、对象等直接写在父构造函数的原型上,所有实例会共享同一份引用。属性独立的前提是:这些属性必须定义在实例自身(即 this)上,而不是原型链上。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ❌ 错误:在
Parent.prototype上设hobbies = []→ 所有实例共用一个数组 - ✅ 正确:在
Parent构造函数体内用this.hobbies = []→ 每个实例初始化自己的数组
组合继承中注意重复调用问题
组合继承(构造函数继承 + 原型链继承)常被推荐,但要注意:父构造函数会被调用两次(一次在子类构造函数内 call,一次在设置 Child.prototype = new Parent() 时),导致原型上多出无用属性。若父构造函数有副作用(如发请求、修改全局状态),需谨慎。
- 优化方案:可用寄生组合式继承(只调用一次父构造函数),用
Object.create(Parent.prototype)设置子类原型 - 或改用 ES6
class+super(),底层自动处理 this 绑定和原型链,更安全简洁
ES6 class 是更现代的解法
语法更清晰,且 super() 自动确保父构造函数在子实例上执行,属性天然独立。
class Parent {
constructor(name, items) {
this.name = name;
this.items = items || [];
}
}
class Child extends Parent {
constructor(name, items, level) {
super(name, items); // 等价于 Parent.call(this, name, items)
this.level = level;
}
}
const a = new Child('A', [1], 'high');
const b = new Child('B', [2], 'low');
a.items.push(3);
console.log(b.items); // [2] —— 完全独立
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










