JavaScript原型链不可变性保障的核心是保护原型对象状态,而非链路结构本身;可通过Object.freeze(浅冻结)、Object.defineProperty(精确控制属性)、避免替换prototype、以及seal/preventExtensions等手段实现。

JavaScript 中原型链查找路径本身是只读的委托机制,不涉及“修改路径”操作;所谓“不可变性保障”,实质是防止原型对象被意外篡改,从而破坏查找行为的一致性与可预期性。核心不在链路结构本身,而在链上各原型对象的状态保护。
冻结原型对象:阻止属性层面的变更
对原型对象调用 Object.freeze() 是最直接的方式。它使原型自身不可扩展、所有现有属性不可写且不可配置——这意味着无法新增、删除或重定义属性,也无法修改属性描述符。
- 适用于构造函数的
prototype对象,例如MyClass.prototype - 注意:仅浅层冻结,若原型上有嵌套对象(如
defaults: { timeout: 500 }),需递归调用Object.freeze或使用deepFreeze - 冻结后,尝试
MyClass.prototype.method = newFn或delete MyClass.prototype.sharedValue均会静默失败(非严格模式)或抛出错误(严格模式)
用 defineProperty 精确控制关键属性
比起整体冻结,有时只需保护特定共享属性(如常量、默认配置、核心方法)。这时应使用 Object.defineProperty 显式设置 writable: false 和 configurable: false:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 设置
writable: false后,该属性值无法被赋值覆盖 - 设置
configurable: false后,该属性无法被删除,也不能再次用defineProperty修改其特性 - 特别注意:这不能阻止实例通过同名赋值进行遮蔽(shadowing),即
inst.sharedValue = 'new'仍会在实例上创建新属性,但不影响原型上的原始值
避免替换整个 prototype 引用
动态重写构造函数的 prototype 属性(如 MyClass.prototype = { ... })会切断已有实例与原原型的连接,导致 instanceof 失效、方法丢失等不可预测行为。
立即学习“Java免费学习笔记(深入)”;
- 一旦实例已创建,就不应替换其构造函数的
prototype - 若需扩展原型,应逐个添加属性(
MyClass.prototype.newMethod = fn),或使用Object.assign(MyClass.prototype, {...})(之后再冻结) - 替换前未重置
constructor也会引发元信息混乱,属于常见疏漏
结合 seal / preventExtensions 控制扩展边界
根据防护粒度选择更轻量的控制方式:
- Object.preventExtensions():禁止添加新属性,但允许修改和删除已有属性
-
Object.seal():在 preventExtensions 基础上,禁止删除属性和修改属性描述符(
enumerable、writable、configurable),但属性值仍可改 - 相比
freeze,它们更适合用于“只增不减”的配置型原型,兼顾灵活性与安全性

















