object.freeze仅浅冻结对象自身属性,嵌套对象需手动递归冻结;它不可逆、不作用于原型链,且object.isfrozen只检测顶层。

Object.freeze 是 JavaScript 中让对象“真正只读”的最直接方式,但它不是万能锁——用对了很可靠,用错了容易误以为数据安全了。
怎么冻结一个对象变量
调用 Object.freeze(obj) 即可,它原地修改对象并返回同一引用,不创建新对象:
- 冻结后,不能改已有属性的值(如
obj.name = "new") - 不能添加新属性(
obj.age = 25失效) - 不能删除属性(
delete obj.name无效) - 不能重定义属性特性(比如用
Object.defineProperty改writable或configurable) - 对象的原型也不能被修改(
obj.__proto__ = null会失败)
在严格模式下,违规操作会抛出 TypeError;非严格模式下则静默忽略。
冻结嵌套对象必须手动递归
Object.freeze 只做浅冻结:它只冻结目标对象自身及其直接属性,对属性值是对象、数组等引用类型时,内部结构完全不受影响。
例如:
const user = { name: "Alice", profile: { city: "Beijing" } };
Object.freeze(user);
user.profile.city = "Shanghai"; // ✅ 成功!profile 未被冻结
user.profile.skills = ["JS"]; // ✅ 也能添加
要真正深冻结,需自己实现或调用工具函数:
- 检查每个属性是否为普通对象(排除
null、原始值、函数、Date、RegExp 等) - 对符合条件的嵌套对象递归调用
Object.freeze - 注意避免循环引用(可用
WeakMap缓存已处理对象)
其他关键局限性
冻结不可逆:JavaScript 没有 Object.unfreeze,一旦冻结,无法恢复可写状态。
不作用于原型链:冻结只影响对象自身的自有属性,继承来的属性仍可能被间接修改(比如通过修改原型上的方法)。
性能与调试影响:V8 引擎会对冻结对象启用特殊标记,可能绕过部分优化;DevTools 中属性名变灰带锁图标,有时会被误读为“数据没加载”;且无法再用 Object.assign 或解构赋值更新字段。
判断是否冻结仅看顶层:Object.isFrozen(obj) 返回 true,只要对象自身满足冻结条件,不管其嵌套对象有没有冻——这点容易造成误判。
替代方案对比(按防护强度)
如果不需要最强防护,可考虑更轻量的选项:
-
Object.preventExtensions():只禁止新增属性,其余都可动 -
Object.seal():禁止新增 + 禁止删除/重配置,但允许改值(若原writable: true) -
Object.freeze():三者中最严,连值也不让改(默认设所有自有属性writable: false)
三者都只作用于当前对象,都不递归。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











