JavaScript 中的属性描述符是定义对象属性行为的元数据,控制可读、可写、可枚举、可配置性;分数据属性(value/writable)和访问器属性(get/set),二者字段互斥;configurable: false 后不可修改任何描述符且无法删除。

什么是 JavaScript 中的属性描述符
属性描述符是 JavaScript 用来定义对象属性行为的一组元数据,它决定了属性是否可读、可写、可枚举、可配置。每个属性(无论是数据属性还是访问器属性)都对应一个描述符对象,可通过 Object.getOwnPropertyDescriptor() 查看,用 Object.defineProperty() 或 Object.defineProperties() 设置。
数据属性 vs 访问器属性的描述符结构
数据属性(如 obj.x = 1)和访问器属性(含 get/set)的描述符字段互斥:不能同时指定 value 和 get,否则会抛出 TypeError: Invalid property descriptor。
- 数据属性描述符包含:
value、writable、enumerable、configurable - 访问器属性描述符包含:
get、set、enumerable、configurable
例如,以下写法会报错:
Object.defineProperty(obj, 'x', {
value: 42,
get() { return this._x; },
writable: true
});
因为 value 和 get 同时存在。
立即学习“Java免费学习笔记(深入)”;
常见控制场景与易错点
实际开发中常需冻结属性行为,但容易忽略 configurable: false 的不可逆性——一旦设为 false,后续无法再用 defineProperty 修改该属性的任何描述符(包括 writable),也无法 delete 它。
-
writable: false只禁写值,不阻止defineProperty修改其他描述符(除非configurable也为false) -
enumerable: false会让该属性不出现在for...in、Object.keys()中,但Object.getOwnPropertyNames()仍能拿到 -
configurable: false后,连把writable: true改回false都会失败
示例:
const obj = {};
Object.defineProperty(obj, 'x', {
value: 100,
writable: false,
configurable: false
});
obj.x = 200; // 无效(非严格模式下静默失败;严格模式抛 TypeError)
Object.defineProperty(obj, 'x', { writable: true }); // TypeError!configurable 为 false 时禁止修改
批量设置与原型链上的陷阱
使用 Object.defineProperties() 批量定义时,每个属性必须提供完整描述符;遗漏字段会被设为默认值(undefined),可能导致意外行为(比如 value 未设则为 undefined,writable 默认为 false)。
更关键的是:属性描述符只作用于**自身属性**,不会影响原型链上的同名属性。如果在原型上定义了 get,又在实例上用 defineProperty 添加同名数据属性(且 configurable: false),就可能遮蔽原型访问器,且再也无法恢复。
- 避免在已有原型访问器的对象上,直接覆盖定义同名数据属性
- 检查是否存在继承来的属性,可用
Object.prototype.hasOwnProperty.call(obj, 'prop') - 批量定义时建议显式写出所有字段,不要依赖默认值
比如这个看似无害的操作:
const proto = {
get x() { return 'from proto'; }
};
const obj = Object.create(proto);
Object.defineProperty(obj, 'x', { value: 'own', configurable: false });
console.log(obj.x); // 'own' —— 原型的 get 被彻底屏蔽,且无法撤回
描述符的真正复杂性不在语法,而在它和原型、严格模式、冻结状态之间的耦合。改一个字段前,最好先确认 configurable 状态,再决定是否值得锁死。










