彻底避免原型链继承中引用属性被修改的关键是不让子类实例共享父类构造函数创建的引用类型属性;推荐使用寄生组合式继承或es6 class,通过parent.call(this)或super()确保每个实例拥有独立引用属性,同时继承原型方法。

彻底避免原型链继承中引用属性被修改,关键在于不让子类实例共享父类构造函数中创建的引用类型属性。传统原型链继承(Child.prototype = new Parent())会让所有子类实例共用同一份 this.colors、this.friends 等,一旦某个实例修改数组或对象,其他实例立刻受影响。
不把父类实例直接设为子类原型
这是最根本的切断点。不要写:
SubClass.prototype = new SuperClass();
因为这会执行父类构造函数,把引用属性挂到原型上,所有子类实例都通过原型链访问同一个数组或对象。
改用寄生组合式继承(推荐方案)
它分两步隔离:原型方法继承 + 实例属性独立初始化。
- 用空函数桥接父类原型,让
Child.prototype只继承Parent.prototype上的方法,完全绕开Parent构造函数执行 - 在子类构造函数里调用
Parent.call(this, ...),确保每个实例拥有自己的一份引用属性(如独立的colors数组)
这样既复用了方法,又杜绝了引用共享。
若必须用纯原型链,至少冻结父类原型上的引用属性
仅适用于只读共享数据(如默认配置),不能解决“每个实例需要独立副本”的需求:
- 对原型上定义的引用属性,用
Object.defineProperty设置writable: false和configurable: false - 若该属性是对象或数组,还需递归调用
Object.freeze()实现浅层不可变
注意:这只能防止在原型层面被改,不能阻止实例赋值遮蔽(child.colors = []),所以不是真正“避免修改”,只是加了一道防护。
更现代的做法:用 class + extends
ES6 的 class 本质就是寄生组合式继承的语法糖,自动处理了原型链接、constructor 修正和 super 绑定:
- 子类构造函数中必须调用
super(),保证父类实例属性独立初始化 - 父类方法定义在
prototype上,不产生共享引用 - 代码清晰、调试友好,且兼容性已覆盖主流环境
只要运行环境支持,应优先使用 class,无需手动实现继承逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











