object.freeze() 默认仅浅冻结对象自身属性,不递归冻结嵌套对象;需用 deepfreeze 手动递归冻结所有层级,配合 const、严格模式及 object.isfrozen 校验可提升安全性。

Object.freeze() 能让对象“表面不可变”——属性无法添加、删除、重配置,已有属性的值也不能被重新赋值(前提是属性是基础类型)。但它不递归冻结嵌套对象,所以要实现“真正不可变”,必须手动处理深层结构。
为什么 Object.freeze() 默认不是“真正不可变”?
它只冻结目标对象自身的属性,对引用类型的属性(如数组、对象)内部不做任何限制。例如:
const config = Object.freeze({
api: { baseUrl: 'https://api.example.com' },
timeout: 5000
});
config.timeout = 10000; // ❌ 失败,基础属性被冻结
config.api.baseUrl = 'https://new.api'; // ✅ 成功!嵌套对象未被冻结
手动递归冻结:简单可靠的方案
写一个工具函数,对对象及其所有嵌套对象/数组逐层调用 Object.freeze():
function deepFreeze(obj) {
if (obj && typeof obj === 'object') {
Object.getOwnPropertyNames(obj).forEach(prop => {
if (obj[prop] && typeof obj[prop] === 'object') {
deepFreeze(obj[prop]); // 递归冻结子对象
}
});
}
return Object.freeze(obj);
}
const constants = deepFreeze({
API: { URL: 'https://api.example.com', VERSION: 'v2' },
DB: { MAX_RETRY: 3, TIMEOUT: 10000 }
});
- 所有层级的对象和数组都被冻结,无法修改其属性或元素
- 注意:Symbol 属性、getter/setter 也会被冻结(但不会执行 setter)
- 原始值(string/number/boolean)本身不可变,无需额外处理
配合 const 和严格模式更安全
仅用 Object.freeze() 还不够,还需配合语言机制防止变量重新赋值:
- 用 const 声明变量,避免重新指向新对象
- 在严格模式(
'use strict')下,给已冻结对象赋值会抛出TypeError,便于及时发现错误 - 开发时可加一层运行时校验:
Object.isFrozen(obj)检查是否生效
替代思路:用 class 封装 + 私有字段(ES2022+)
若需更强封装性,可用私有字段 + getter 模拟只读常量:
class Constants {
#data = {
API_URL: 'https://api.example.com',
MAX_ITEMS: 100
};
constructor() {
Object.freeze(this.#data); // 冻结内部数据
}
get API_URL() { return this.#data.API_URL; }
get MAX_ITEMS() { return this.#data.MAX_ITEMS; }
}
const CONST = new Constants();
- 外部无法访问或修改
#data,也无法覆盖 getter - 适合需要逻辑控制或延迟初始化的场景
- 仍建议对
#data手动freeze,防止内部误操作
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











