确保原型属性不被意外覆盖的关键是通过 object.defineproperty 在原型上设置 writable: false 和 configurable: false,或使用访问器配合私有字段,或冻结整个原型对象,并避免在实例上创建同名自有属性。

要确保原型属性不被意外覆盖,关键不是“防止别人改”,而是让实例无法通过简单赋值创建同名自身属性来遮蔽它——这靠的是在原型上正确定义属性描述符,而不是靠约束使用者。
用 Object.defineProperty 设置原型属性
直接在原型对象上调用 Object.defineProperty,并设 writable: false 和 configurable: false:
- 设置 writable: false 后,实例执行
obj.prop = value不会修改原型值,非严格模式下静默失败,严格模式下抛TypeError - 设置 configurable: false 后,该属性无法被删除,也无法再次用
defineProperty修改描述符 - 避免在实例上调用
Object.defineProperty(obj, 'prop', ...),否则会创建遮蔽属性,反而绕过保护
优先用访问器统一控制读写
在原型上定义 get/set,把逻辑收口到一处:
- 所有实例访问
obj.prop都走同一个 getter,不会因实例赋值而失效 - 配合
configurable: false,可阻止实例用obj.prop = ...创建数据属性覆盖访问器 - 内部用私有字段(如
_prop)存值,避免与属性名冲突
冻结整个原型对象
若原型上多数属性都应只读且不可变,直接调用 Object.freeze(Person.prototype):
- 它会将原型上所有自有属性设为
writable: false和configurable: false - 不影响实例自身属性,也不影响更上层原型(如
Object.prototype) - 必须在添加完所有方法和属性后调用,冻结后再加属性会失败
避开常见遮蔽陷阱
很多“覆盖”其实只是实例无意中创建了同名自有属性:
- 避免在构造函数或初始化逻辑里写
this.prop = ...,除非你明确需要实例独有副本 - 检查是否用了
Object.assign(instance, data)或展开运算符合并外部数据——它们会把键直接写到实例上,可能覆盖原型方法 - 遍历时用
hasOwnProperty过滤,但注意:obj.hasOwnProperty('prop')本身可能被污染,推荐用Object.prototype.hasOwnProperty.call(obj, 'prop')











