util.inherits继承中子类修改原型对象为何影响父类及其他子类?
为什么修改Child原型的container会影响Parent和其他子类?
这是个典型的原型链引用类型共享陷阱,我来给你一步步拆解原因:
核心问题:引用类型的原型属性是共享的
你代码里的Parent.prototype.container = {}是一个引用类型(对象),而util.inherits(Child, Parent)做的事情是把Child.prototype的原型指向Parent.prototype(等价于Child.prototype.__proto__ = Parent.prototype),而非把Parent原型的属性复制一份给Child原型。
当你执行Child.prototype.container['field'] = function(){}时,JavaScript会先在Child.prototype上查找container属性——但你并没有给Child.prototype单独定义过container,所以它会沿着原型链向上找到Parent.prototype.container,然后直接修改这个同一个对象的field属性。
这就导致:
Parent.prototype.container自然会有field,因为你直接改的就是它- 后来的
AnotherChild通过util.inherits继承Parent后,访问AnotherChild.prototype.container时,同样会找到Parent原型上那个被修改过的container对象,所以也会带有field属性
怎么解决?让每个子类拥有独立的container
如果你想让每个子类(包括Parent实例)的container都是独立的,有两种常见方案:
方案1:在构造函数里初始化实例的container
把container定义为实例属性,而非原型属性:
const util = require('util'); function Parent() { // 每个Parent实例都会有自己的container this.container = {}; } function Child() { Parent.call(this); // 调用父类构造函数,初始化自己的container } util.inherits(Child, Parent); // 现在修改Child实例的container不会影响Parent或其他子类 const child = new Child(); child.container['field'] = function(){}; const parent = new Parent(); console.log(parent.container.field); // undefined,符合预期
方案2:给子类原型单独创建新的container对象
如果你确实需要把container放在原型上(不推荐用于可变引用类型),可以给Child原型单独赋值一个新对象,覆盖原型链的查找:
const util = require('util'); function Parent() {} Parent.prototype.container = {}; function Child() { Parent.call(this); } util.inherits(Child, Parent); // 给Child原型创建独立的container,不再共享Parent的 Child.prototype.container = {}; Child.prototype.container['field'] = function(){}; const parent = new Parent(); console.log(parent.container.field); // undefined,符合预期 function AnotherChild() { Parent.call(this); } util.inherits(AnotherChild, Parent); console.log(AnotherChild.prototype.container.field); // undefined,符合预期
总结
- 原型上的引用类型属性会被所有继承该原型的实例/子类共享
util.inherits只是建立原型链关联,不会复制原型属性- 要避免这类问题,尽量把可变的引用类型定义为实例属性(在构造函数里初始化)
内容的提问来源于stack exchange,提问作者sent1nel
相关产品推荐
相关产品推荐

