原型重写会立即更新对象的[[prototype]]指针,切断原有继承关系,后续属性查找仅基于新原型链;构造函数prototype重写不影响已有实例;class原型不可写,应优先使用继承或组合替代。

当对象的原型被重写(比如直接赋值 obj.__proto__ = newProto 或通过 Object.setPrototypeOf(obj, newProto)),JavaScript 会立即更新该对象的内部 [[Prototype]] 指针,后续属性查找将基于新原型链进行,旧原型上的属性不再可访问(除非新原型显式继承它)。
原型重写会切断原有继承关系
原型链查找依赖对象内部的 [[Prototype]] 链。一旦重写,原链断裂,查找逻辑从新原型开始,不会“记住”或回溯旧原型。
- 例如:`let a = {}; let b = {x: 1}; a.__proto__ = b; console.log(a.x); // 1`;之后执行 `a.__proto__ = {};`,再访问 `a.x` 就是 `undefined` —— 不会再去查原来的 `b`
- 构造函数的 `prototype` 属性被重写(如 `C.prototype = {}`),只影响此后用 `new C()` 创建的对象,不影响已创建实例的 [[Prototype]]
重写时要注意 constructor 属性丢失
新原型对象通常没有 `constructor` 属性,或指向错误构造器,这虽不影响查找逻辑,但可能干扰 instanceof 判断和反射类行为。
- 建议手动修复:`NewProto.constructor = MyConstructor;`
- 更稳妥的方式是用 `Object.create(OriginalProto)` 继承原有原型,再扩展,而非完全替换
避免意外覆盖 Object.prototype
全局修改 `Object.prototype`(如 `Object.prototype.foo = ...`)会影响所有普通对象的原型链查找,极易引发冲突和性能问题。
- 现代代码应禁用此类操作;若必须扩展,优先使用 `Object.defineProperty` 并设 `writable: false, enumerable: false`
- 检查属性是否存在时,用 `hasOwnProperty` 或 `Object.prototype.hasOwnProperty.call(obj, 'key')` 避免受原型污染干扰
ES6 class 中的限制与替代方案
class 声明的原型对象是不可写的(`writable: false`),直接赋值 `MyClass.prototype = ...` 在严格模式下会静默失败或抛错。
- 如需动态调整行为,推荐组合:用普通对象封装逻辑,通过实例属性或代理(Proxy)委托调用
- 继承新类(`class NewClass extends OldClass`)比重写原型更安全、语义更清晰
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











