object.preventextensions仅禁止添加新属性,不限制已有属性的读写、删除或配置修改;它通过将对象[[extensible]]内部槽设为false实现,不可逆且不递归作用于嵌套对象。

Object.preventExtensions 会改变对象的哪些行为
调用 Object.preventExtensions 后,对象进入“不可扩展”状态:不能再添加新属性(包括通过点号、方括号、Object.defineProperty),但已有属性仍可读、写、删除、重配置(只要它们本身没被 Object.defineProperty 设为不可配置)。
它只影响“属性存在性”,不冻结值、不锁定描述符、不阻止 delete —— 这点常被误认为等同于 Object.freeze,其实差很远。
为什么 Object.preventExtensions 不阻止 delete 操作
因为它的设计目标就是「封顶不封底」:限制新增,不限制移除。JavaScript 规范明确将 preventExtensions 和 seal/freeze 分开定义,前者只修改对象内部的 [[Extensible]] 内部槽位为 false,而 delete 是否成功取决于属性自身的 configurable 值,与对象是否可扩展无关。
常见误判场景:
- 试图用它来“保护数据不丢失” → 错,
delete obj.existingKey依然成功 - 以为它会让
in检查变慢或失效 → 不会,"key" in obj行为完全不变 - 在 Proxy 中重复调用 → 无效,多次调用等价于一次,且无法撤销
实际使用时要注意的三个细节
它只作用于目标对象本身,不递归处理嵌套对象:
-
Object.preventExtensions({ a: { b: 1 } })→ 外层不能加属性,但obj.a.c = 2仍合法 - 如需深层防护,得手动遍历或配合
Object.freeze - 对数组也生效:
Object.preventExtensions([])后,arr.push()或arr[3] = x会静默失败(非严格模式)或抛TypeError(严格模式) - 检测是否已不可扩展:用
Object.isExtensible(obj) === false,别依赖try/catch
和 Object.seal / Object.freeze 的关键区别在哪
三者是递进关系,但行为边界清晰:
-
Object.preventExtensions:仅禁新增;已有属性可删、可改值、可改描述符 -
Object.seal=preventExtensions+ 所有现有属性configurable: false→ 禁新增、禁删、禁改描述符,但值仍可改 -
Object.freeze=seal+ 所有现有属性writable: false→ 完全只读(浅层)
所以如果你只要“不让别人乱加字段”,比如防止意外覆盖原型方法或拼错 key,Object.preventExtensions 就够了;想锁死结构再加一层 seal;真要防篡改值,才上 freeze。
最易忽略的是:它不改变属性的 enumerable 或 writable,也不影响 Object.keys、for...in 的结果 —— 这些都照常工作。










