原型链继承本身会导致父类引用类型属性被所有子类实例共享而引发“污染”,真正解决该问题的是组合继承(构造函数继承+原型链继承):前者使每个子类实例拥有独立的实例属性,后者复用父类原型方法,从而隔离引用类型数据。

原型链本身不能直接“解决”父类属性共享污染问题,反而如果使用不当,正是造成污染的根源。真正起作用的是构造函数继承 + 原型链继承的组合方式——它把实例属性和原型方法分开处理,从而避免子类实例间因共享引用类型属性而互相影响。
为什么父类属性会“污染”?
问题出在只用原型链继承时,子类原型被设为父类实例:
// 错误示范:仅用原型链继承Child.prototype = new Parent();
此时 Parent 构造函数被执行一次,其内部的 this.colors = ['red', 'blue'] 成为所有 Child 实例共享的引用值。一个实例 push,其他全变。
组合继承:切断引用属性共享
核心思路是两步分离:
– 实例属性(含引用类型)通过 Parent.call(this, ...) 在每个子类实例中独立创建
– 原型方法通过 Child.prototype = Object.create(Parent.prototype) 复用,不重复执行父构造函数
- 每个
new Child()都调用一次Parent构造函数,生成自己独有的colors数组 -
Child.prototype只继承Parent.prototype上的方法(如sayName),不携带实例数据 - 修复子类 constructor 指向:
Child.prototype.constructor = Child
更优方案:寄生组合继承(推荐)
它优化了组合继承中父构造函数被调用两次的问题(一次在组合继承的 Child.prototype = new Parent(),一次在 Parent.call())。现代标准做法:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
Object.create(Parent.prototype)设置子类原型,避免执行父构造函数 - 再用
Parent.call(this)继承实例属性 - 完整示例:
function Parent(name) {<br>
this.name = name;<br>
this.colors = ['red'];<br>
}<br>
Parent.prototype.say = function() { console.log(this.name); };<br>
<br>
function Child(name, age) {<br>
Parent.call(this, name); // ✅ 各自拥有独立 colors<br>
this.age = age;<br>
}<br>
Child.prototype = Object.create(Parent.prototype); // ✅ 方法复用,无副作用<br>
Child.prototype.constructor = Child;
额外防护:避免原型链污染本身
所谓“污染”,常指意外修改 Object.prototype 或构造函数的 prototype,导致全局行为异常。防范要点:
- 永远不要直接赋值
obj.__proto__ = ...或Object.prototype.xxx = ... - 需要创建干净对象时,用
Object.create(null) - 动态设置属性前校验键名,过滤
__proto__、constructor、prototype - 优先使用
Object.defineProperty控制属性可枚举性与可写性

















