直接修改原型对象的属性或方法会影响所有已有实例,因为实例通过[[Prototype]]链指向同一原型对象;但替换整个prototype只影响新实例,因已有实例的[[Prototype]]仍指向旧对象。

直接修改原型对象的属性或方法,就能影响所有已有实例——前提是修改的是**已有原型对象上的内容**,而不是替换整个原型对象。
改原型对象本身,不是换掉它
构造函数的 prototype 是一个对象,实例通过内部 [[Prototype]] 链指向它。只要不切断这个链接,后续对这个原型对象的增、删、改操作,都会被所有已存在和新创建的实例感知到。
- ✅ 正确:在原有原型上添加方法或覆盖已有方法
Person.prototype.sayHi = function() { console.log('Hi!') };
→ 所有new Person()实例立刻能调用sayHi - ✅ 正确:修改原型上的共享引用类型属性(如数组、对象)
Person.prototype.hobbies = ['reading'];person1.hobbies.push('coding');
→person2.hobbies也会变成['reading', 'coding'](因为共用同一份内存) - ❌ 错误:直接赋值替换整个 prototype
Person.prototype = { sayHello() { ... } };
→ 已创建的实例仍指向旧原型,不会获得新方法;只有之后new Person()的实例才用新原型
为什么已有实例不受影响?看原型链本质
每个实例的 [[Prototype]] 在创建时就固定指向当时的 Person.prototype 对象。如果之后你写 Person.prototype = {...},只是让 Person.prototype 这个变量指向一个新对象,但老实例的内部链接没变,依然连着旧对象。
类比:多个孩子都认同一个妈妈(原型)。你给这位妈妈教新技能(加方法),孩子们马上能学;但如果你换了个“新妈妈”(重赋 prototype),老孩子们还是跟着原来的妈妈,新出生的孩子才跟新妈妈。
想让已有实例也用新原型?不推荐,但技术上可行
可以用 Object.setPrototypeOf(instance, newProto) 逐个修改已有实例的内部原型:
Object.setPrototypeOf(person1, NewPerson.prototype);Object.setPrototypeOf(person2, NewPerson.prototype);
⚠️ 注意:这会破坏引擎优化,性能差;不能用于 Object.freeze() 或不可扩展对象;仅限调试或特殊场景,生产环境避免使用。
确保 constructor 指向正确(附带说明)
如果真要重写原型(比如用对象字面量批量定义),记得补上 constructor:
- 显式设置:
Person.prototype = { constructor: Person, sayHello() { ... } }; - 更严谨方式:
Object.defineProperty(Person.prototype, 'constructor', { value: Person, enumerable: false });
否则 person1.constructor 会返回 Object,语义错乱。











