Object.seal 锁定对象结构但不阻止 getter/setter:禁止增删属性、修改描述符,允许调用已有 accessor;需先定义 accessor 再 seal,否则报错;相比 freeze,seal 兼容可控赋值。

Object.seal 不能阻止 getter/setter 的行为,但能配合它们实现“结构只读 + 属性可读写”的保护效果:封住对象的扩展性与属性描述符的修改权限,同时保留对已有 accessor 属性的访问和赋值能力。
seal 的真实作用:锁住结构,不锁住值
Object.seal(obj) 执行后:
- 禁止添加新属性(
obj.newProp = 1失效) - 禁止删除已有属性(
delete obj.prop失效) - 禁止修改属性的描述符(如
writable、configurable、enumerable)——这是关键 - 但允许修改 已存在且 writable 为 true 的数据属性 的值
- 也允许调用已存在的 getter/setter —— 因为 accessor 属性本身是
configurable: false(seal 后不可改),但set方法仍可执行
配合 getter/setter 的典型用法
先定义带 getter/setter 的属性,再 seal,就能让对象“结构固定、内部状态可控”:
const person = {
_name: 'Alice',
_age: 30
};
// 添加 accessor 属性(默认 configurable: true,所以 seal 前必须设好)
Object.defineProperty(person, 'name', {
get() { return this._name; },
set(value) { this._name = String(value).trim(); }
});
Object.defineProperty(person, 'age', {
get() { return this._age; },
set(value) {
if (Number.isInteger(value) && value >= 0) {
this._age = value;
} else {
throw new Error('Age must be a non-negative integer');
}
}
});
Object.seal(person); // 封住结构:不能增删属性,也不能改 descriptor
此时:
立即学习“Java免费学习笔记(深入)”;
-
person.name = 'Bob'✅ 正常触发 setter -
person.age = 35✅ 校验通过,更新成功 -
person.height = 170❌ 静默失败(严格模式下报错) -
delete person.name❌ 失败(seal 禁止删除) -
Object.defineProperty(person, 'name', { value: 'X' })❌ 报错(configurable 已被 seal 锁死)
注意:seal 前必须完成 accessor 定义
因为 seal 会把所有属性的 configurable 设为 false,而 accessor 必须在 configurable: true 时才能定义(否则 defineProperty 会报错)。所以顺序不能颠倒:
- ✅ 先
defineProperty(此时 configurable 默认 true) - ✅ 再
Object.seal(自动设所有 descriptor 的 configurable 为 false) - ❌ 反过来:seal 后再 defineProperty 添加 accessor → 报错 “Cannot define property … on sealed object”
和 Object.freeze 的区别要清楚
如果希望连 person.name = 'xxx' 这类赋值也禁止,那就该用 freeze;但 freeze 会让 setter 失效(因为 freeze 把所有数据属性设为 writable: false,而 accessor 不受影响 —— 但你通常不会在 freeze 对象上定义 setter,因为 freeze 后无法 defineProperty)。
简言之:
-
seal→ 结构冻结 + accessor 仍可用 -
freeze→ 结构冻结 + 值冻结(数据属性不可改,accessor 若存在仍可触发,但极少这么用)
真正需要“只读接口 + 可控变更”的场景,seal + accessor 是更灵活的选择。


















