Object.defineProperty 详解
Object.defineProperty() 是 JavaScript 中一个强大的方法,用于直接在对象上定义新属性或修改现有属性,并返回该对象。它提供了对属性行为的精细控制。
基本语法
Object.defineProperty(obj, prop, descriptor)
obj:要在其上定义属性的对象prop:要定义或修改的属性的名称descriptor:将被定义或修改的属性描述符
属性描述符
属性描述符有两种主要类型:数据描述符和存取描述符。
数据描述符
数据描述符是一个具有以下可选键的对象:
value:属性的值,默认为undefinedwritable:是否可写,true表示可修改,默认为falseenumerable:是否可枚举,true表示会出现在对象的枚举属性中,默认为falseconfigurable:是否可配置,true表示该属性的类型可以改变,且属性可以从对象中删除,默认为false
存取描述符
存取描述符是一个具有以下可选键的对象:
get:作为该属性的 getter 函数,默认为undefinedset:作为该属性的 setter 函数,默认为undefinedenumerable:同数据描述符configurable:同数据描述符
注意:描述符不能同时是数据描述符和存取描述符(即不能同时有 value/writable 和 get/set)。
示例
1. 基本使用
const obj = {};
// 添加数据属性
Object.defineProperty(obj, 'name', {
value: 'John',
writable: true,
enumerable: true,
configurable: true
});
console.log(obj.name); // "John"
2. 不可写属性
const obj = {};
Object.defineProperty(obj, 'readOnly', {
value: 42,
writable: false
});
obj.readOnly = 100; // 静默失败,严格模式下会报错
console.log(obj.readOnly); // 42
3. 不可枚举属性
const obj = {};
Object.defineProperty(obj, 'hidden', {
value: 'secret',
enumerable: false
});
console.log(obj.hidden); // "secret"
console.log(Object.keys(obj)); // []
4. 使用 getter 和 setter
const obj = {};
let internalValue = '';
Object.defineProperty(obj, 'greeting', {
get: function() {
return internalValue;
},
set: function(value) {
internalValue = 'Hello, ' + value;
},
enumerable: true,
configurable: true
});
obj.greeting = 'World';
console.log(obj.greeting); // "Hello, World"
5. 不可配置属性
const obj = {};
Object.defineProperty(obj, 'fixed', {
value: 'cannot change',
configurable: false
});
// 尝试删除或修改属性描述符会失败
delete obj.fixed; // false
console.log(obj.fixed); // "cannot change"
// 严格模式下会抛出错误
Object.defineProperty(obj, 'fixed', { configurable: true }); // 抛出 TypeError
注意事项
- 默认值:如果不显式指定,
writable、enumerable和configurable的默认值都是false。 - 严格模式:在非严格模式下,违反属性描述符限制的操作会静默失败;在严格模式下会抛出错误。
- 继承:通过
Object.defineProperty()定义的属性默认是不可枚举的,因此不会出现在for...in循环中(除非显式设置enumerable: true)。 - 性能:与普通属性相比,访问器属性(getter/setter)可能会有轻微的性能开销。
实际应用
Object.defineProperty() 常用于:
- 创建不可变属性
- 实现数据绑定和观察(如 Vue 2.x 的响应式系统)
- 定义隐藏属性(不可枚举)
- 实现高级属性行为(如计算属性、验证等)
浏览器兼容性
Object.defineProperty() 在 IE9+ 和所有现代浏览器中都支持,但在 IE8 中仅能用于 DOM 对象。