object.freeze 仅浅层冻结对象自身直接属性,使其不可扩展、不可删除,且自有属性的 configurable 和 writable 均设为 false,但不递归冻结嵌套对象;深冻结需手动递归实现。

Object.freeze 可以冻结对象,使其不可扩展、不可删除已有属性,且所有自有属性的 writable 和 configurable 都被设为 false。但它只作用于对象自身的**直接属性**,不递归冻结嵌套对象。
冻结后属性描述符的确变为不可配置
调用 Object.freeze(obj) 后,对象自身所有自有属性的描述符中:
– configurable 变为 false(无法 delete、无法 redefine)
– writable 变为 false(若原为数据属性)
– enumerable 保持不变
– get/set 访问器属性同样变为不可配置(无法修改或删除)
验证方式:
- 用
Object.getOwnPropertyDescriptor(obj, 'prop')查看具体属性描述符 - 尝试
delete obj.prop或Object.defineProperty(obj, 'prop', {...})会静默失败(严格模式下抛TypeError)
注意:freeze 不递归,嵌套对象仍可变
如果对象某个属性值本身是对象(如 {a: {b: 1}}),Object.freeze 不会自动冻结 a 所指的对象。
例如:
const obj = { nested: { x: 1 } };
Object.freeze(obj);
obj.nested.x = 2; // ✅ 允许(nested 对象未被冻结)
obj.nested.y = 3; // ✅ 允许(nested 仍可扩展)
如需完全冻结,需手动递归处理或使用深冻结函数。
深冻结需递归调用 freeze
要让整个对象树(包括所有嵌套对象)都不可配置、不可写,需自行实现递归冻结:
- 检查属性值是否为普通对象(排除 null、数组、Date、RegExp 等)
- 对每个对象类型的属性值递归调用
Object.freeze - 最后再冻结父对象本身(避免先冻结父对象导致子对象无法访问)
简易深冻结示例:
function deepFreeze(obj) {
if (obj !== null && typeof obj === 'object' && !Object.isFrozen(obj)) {
Object.getOwnPropertyNames(obj).forEach(prop => {
deepFreeze(obj[prop]);
});
return Object.freeze(obj);
}
return obj;
}
冻结后仍可读取和遍历
冻结不影响属性的可读性或枚举性:
– obj.prop、for...in、Object.keys() 等均正常工作
– 仅限制修改行为(赋值、重定义、删除)
– Object.isFrozen(obj) 可检测是否已冻结
冻结是浅层的、单向的保护机制,适合构建不可变配置或常量对象,但不能替代类型系统或运行时校验。











