object.defineproperty 可精确控制属性的可读、可写、可枚举和可配置性;其描述符含 value/writable/enumerable/configurable 四字段,支持定义常量、只读属性及 getter/setter,但需注意默认值及重定义限制。

使用 Object.defineProperty 可以精确配置对象属性的可读性、可写性、可枚举性和可配置性,它比直接赋值或使用字面量定义更底层、更可控。
理解四个核心描述符
每个属性都有一个属性描述符对象,包含以下关键字段:
- value:属性的值(仅用于数据属性)
-
writable:是否可修改该值(
true或false) -
enumerable:是否可在
for...in或Object.keys()中遍历到 -
configurable:是否可删除该属性,或再次调用
defineProperty修改其描述符(注意:configurable: false后不能再改writable为true,也不能从数据属性转为访问器属性)
定义不可修改的常量属性
想让某个属性像常量一样不能被覆盖或删除,可以这样设置:
const obj = {};
Object.defineProperty(obj, 'VERSION', {
value: '1.2.0',
writable: false,
enumerable: true,
configurable: false
});
// obj.VERSION = '2.0'; // 无效(严格模式下会报错)
// delete obj.VERSION; // 失败,返回 false
此时 VERSION 在遍历中可见,但无法改写、删除或重新配置。
创建只读但可枚举的属性
有时需要属性能被遍历,但不允许意外修改,比如暴露内部状态:
- 设
writable: false阻止赋值 - 设
enumerable: true保证Object.keys(obj)能看到它 - 设
configurable: false更安全;若需后期调整,可设为true
注意:即使 writable: false,只要 configurable: true,仍可通过再次调用 defineProperty 改为可写(但不推荐,违背只读初衷)。
定义 getter/setter 控制访问逻辑
当属性需要计算、校验或副作用时,用访问器属性代替 value 和 writable:
let _name = '';
Object.defineProperty(obj, 'name', {
get() { return _name; },
set(value) {
if (typeof value === 'string' && value.trim()) {
_name = value.trim();
}
},
enumerable: true,
configurable: true
});
此时不能同时指定 value 或 writable,否则会报错。访问器属性默认 enumerable 和 configurable 都是 false,必须显式声明才生效。
常见陷阱与注意事项
直接在普通对象上使用时,容易忽略几个关键点:
- 目标对象必须存在,且属性名必须是字符串或 Symbol
- 对已有属性重定义时,如果原属性是
configurable: false,只能修改writable(且仅限从true→false) - 在严格模式下,对不可写属性赋值会抛出
TypeError;非严格模式下静默失败 - 使用
Object.defineProperty定义的属性,默认enumerable和configurable都是false,务必按需显式设置











