Object.isFrozen仅检测对象是否被冻结,不拦截操作;它返回布尔值,不阻止赋值,需配合Proxy等机制才能真正拦截修改。

Object.isFrozen 本身不能拦截操作,只能检测状态
Object.isFrozen 是一个只读检测函数,它不阻止任何赋值或修改行为,只返回 true 或 false。很多人误以为调用它就能“拦住”修改,其实它像一个体温计——告诉你对象是不是冻住了,但不会帮你关空调。
常见错误现象:
在 setter 或更新逻辑里只写 if (Object.isFrozen(obj)) { throw new Error(...) },却没意识到:此时属性可能已经被改过了(比如对象是浅冻结,嵌套对象仍可变);或者根本没在真正赋值前检查(比如直接用了 obj.prop = value,再检查就晚了)。
- 它只检测对象自身是否被
Object.freeze()(或Object.seal()、Object.preventExtensions())处理过 - 对普通对象、
null、基本类型都返回false;对已冻结对象返回true - 它不递归检查嵌套对象——
Object.isFrozen({ a: { b: 1 } })返回true,但obj.a.b = 2依然合法
想真正拦截,得把 Object.isFrozen 放进代理或封装层
真正能“拦截”的只有 Proxy。你可以用 Object.isFrozen 作为判断依据,在 set 捕获器里做决策:
const createProtectedProxy = (obj) => {
return new Proxy(obj, {
set(target, key, value) {
if (Object.isFrozen(target)) {
throw new TypeError(`Cannot assign to read-only property '${key}' of frozen object`);
}
target[key] = value;
return true;
}
});
};
使用场景:
适合封装配置对象、运行时不可变的上下文(如 env、constants),需要明确报错而非静默失败。
- 注意:
Object.isFrozen在set中调用是安全的,但别在get里频繁调用——它开销虽小,但无谓检查会累积 - 如果目标对象是深度冻结(手动递归 freeze),
Object.isFrozen仍只管顶层,所以更稳妥的做法是把冻结状态存在闭包或 Symbol 属性里 - 不要依赖
Object.isFrozen来替代权限控制——它防不住主动绕过 Proxy 的直接操作
和 Object.isSealed / Object.isExtensible 的关键区别
三者常被混淆,但冻结(frozen)是最强约束:
-
Object.isExtensible(obj):只看能否添加新属性(true表示还能加) -
Object.isSealed(obj):比 extensible 多一层——不能加/删属性,但已有属性仍可改值(writable: true时) -
Object.isFrozen(obj):最严——不能加/删属性,且所有自有属性的writable都为false(即不能改值)
所以如果你只调用了 Object.seal(),Object.isFrozen() 会返回 false,即使你主观上认为“这该算只读”。别用错检测函数,否则拦截逻辑就失效了。
容易忽略的兼容性与性能点
Object.isFrozen 在 IE 中完全不支持(Edge 12+、Chrome 30+、Firefox 30+ 才有),如果要兼容旧环境,必须降级处理或提前 polyfill:
if (typeof Object.isFrozen !== 'function') {
Object.isFrozen = (obj) => {
if (obj === null || typeof obj !== 'object') return false;
return !Object.isExtensible(obj) &&
Object.keys(obj).every(key => !Object.getOwnPropertyDescriptor(obj, key).writable);
};
}
性能影响很小,但要注意:它内部会遍历自有属性并调用 getOwnPropertyDescriptor,对超大对象(>10k 属性)可能微卡。生产中若高频校验,建议缓存结果(例如用 WeakMap 存冻结状态),而不是每次调用都查。
最常被忽略的是:冻结检查必须发生在赋值动作之前,且需覆盖所有修改入口(包括 Object.assign、解构赋值、Reflect.set 等)。靠单点 Object.isFrozen 调用,永远拦不住所有非法操作。

















