← 返回题目列表

Object.freeze、Object.seal 和 Object.preventExtensions 有什么区别?

高频 中等 第 15 / 29 题 更新于 2026/07/29
JavaScriptObject对象属性

简化版

preventExtensions 只禁止新增属性;seal 禁止新增和删除属性,并把属性设为不可配置;freeze 在 seal 的基础上让数据属性不可写,是三者中限制最强的。

详细版

三者都只对对象第一层生效:

Object.preventExtensions(obj);
Object.seal(obj);
Object.freeze(obj);

区别:

  • preventExtensions:不能新增属性,已有属性可改可删。
  • seal:不能新增,不能删除,属性不可配置,但可写属性仍可改值。
  • freeze:不能新增,不能删除,不能改已有数据属性值。

面试重点是限制层级、是否深冻结、严格模式下失败赋值会不会报错。

完整版教学

一、对象属性有多种描述维度

理解这三个 API 前,要先知道对象属性不只有值。 属性还有 writableconfigurableenumerable 等描述符。 这些 API 本质是在批量调整对象的扩展性和属性描述符。

const obj = { a: 1 };
console.log(Object.getOwnPropertyDescriptor(obj, 'a'));

一个普通数据属性通常类似:

value: 1
writable: true
enumerable: true
configurable: true

freeze/seal/preventExtensions 改的不是原型链魔法,而是这些底层开关。

二、preventExtensions 只关掉新增能力

Object.preventExtensions(obj) 会让对象不能再添加新属性。 已有属性仍然可以修改,也可以删除,只要属性本身允许。 它是三者里限制最轻的。

const obj = { a: 1 };
Object.preventExtensions(obj);

obj.a = 2;
delete obj.a;
obj.b = 3;

console.log(obj); // {}

在非严格模式下,新增 b 可能静默失败。 严格模式下,给不可扩展对象新增属性会抛错。 因此面试回答要区分语义限制和运行模式表现。

三、seal 会固定属性集合

Object.seal(obj) 等价于禁止扩展,并把已有自有属性设为不可配置。 不可配置意味着不能删除,也不能重新定义很多描述符。 但如果数据属性仍是可写的,值还可以改。

const obj = { a: 1 };
Object.seal(obj);

obj.a = 2;
delete obj.a;
obj.b = 3;

console.log(obj); // { a: 2 }

流程可以理解为:

seal
  -> preventExtensions
  -> configurable: false
  -> writable 保持原状

这适合“对象结构不能变,但属性值可以更新”的场景。

四、freeze 是最强限制

Object.freeze(obj) 在 seal 的基础上,把已有数据属性设为不可写。 也就是说不能新增、不能删除、不能改值。 它常用于常量配置、防止枚举对象被改写等场景。

const config = Object.freeze({ timeout: 3000 });
config.timeout = 1000;

console.log(config.timeout); // 3000
API可新增可删除可改已有值强度
preventExtensions
seal
freeze

如果在严格模式下修改冻结属性,会抛出 TypeError。 这有助于开发期尽早发现错误。

五、它们默认都是浅层的

这三个 API 只处理对象自身第一层属性。 如果属性值还是对象,嵌套对象内部仍然可以修改。 这点非常高频。

const obj = Object.freeze({
  nested: { count: 1 }
});

obj.nested.count = 2;
console.log(obj.nested.count); // 2

如果需要深冻结,要递归处理每个嵌套对象。 但深冻结有遍历成本,还要处理循环引用、函数对象等边界。 工程中不应无脑对大对象深冻结。

六、如何检查对象状态

JavaScript 提供了对应检查方法。 它们可以帮助调试,也常出现在笔试题里。

Object.isExtensible(obj);
Object.isSealed(obj);
Object.isFrozen(obj);

记忆钩子:扩展性管“能不能加”,配置性管“能不能删和改描述符”,可写性管“能不能改值”。

如果对象被冻结,通常也是 sealed 和不可扩展的。 但 sealed 对象不一定 frozen,因为属性值可能仍可写。

七、常见误区与追问

  • 误区:freeze 会递归冻结所有嵌套对象。 默认只冻结第一层,嵌套对象仍可变。
  • 误区:seal 后属性值也不能改。 seal 固定属性集合和配置性,可写属性仍能改值。
  • 误区:非严格模式下失败操作一定报错。 很多失败赋值在非严格模式下会静默失败,严格模式才抛错。
  • 追问:如何判断对象是否被冻结? 使用 Object.isFrozen(obj)
  • 追问:freezeconst 有什么区别? const 固定变量绑定,freeze 限制对象属性修改。
  • 追问:为什么深冻结要谨慎? 它需要递归遍历对象图,可能遇到循环引用和性能成本。

八、加强记忆

按限制强度记:preventExtensions 不让加,seal 不让加也不让删,freeze 不让加删改。再补浅层限制和严格模式报错差异,就能把这题答完整。