JavaScript对象属性描述符
属性描述符:JavaScript 对象属性的精细控制
属性描述符是 JavaScript 中用于定义或修改对象属性行为的对象。通过属性描述符,开发者可以精确控制属性的可写性、可枚举性、可配置性,甚至可以通过 get
和 set
方法实现计算属性。
1. 属性描述符的基本结构
使用 Object.getOwnPropertyDescriptor
方法可以获取一个对象属性的描述符。描述符包含以下可选键值:
value
: 属性的值(仅适用于数据属性)。writable
: 布尔值,表示属性是否可写。enumerable
: 布尔值,表示属性是否可枚举(例如,是否出现在for...in
循环中)。configurable
: 布尔值,表示属性是否可配置(例如,是否可以删除或修改描述符)。get
: 函数,表示属性的 getter(仅适用于访问器属性)。set
: 函数,表示属性的 setter(仅适用于访问器属性)。
Object.getOwnPropertyDescriptor(obj, prop);
obj
: 要查询的对象。prop
: 要查询的属性名(字符串或 Symbol)。
2. 定义和获取属性描述符
2.1 定义属性描述符
使用 Object.defineProperty()
或 Object.defineProperties()
方法可以定义或修改对象的属性描述符。
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'Alice',
writable: false, // 不可写
enumerable: true, // 可枚举
configurable: false // 不可配置
});
console.log(obj.name); // 输出: Alice
obj.name = 'Bob'; // 无效,因为 writable 为 false
console.log(obj.name); // 输出: Alice
2.2 获取属性描述符
使用 Object.getOwnPropertyDescriptor()
方法可以获取对象属性的描述符。
const descriptor = Object.getOwnPropertyDescriptor(obj, 'name');
console.log(descriptor);
// 输出: { value: 'Alice', writable: false, enumerable: true, configurable: false }
3. 使用场景
3.1 防止属性被修改或删除
通过设置 writable
和 configurable
为 false
,可以保护属性不被修改或删除。
Object.defineProperty(obj, 'id', {
value: 123,
writable: false,
configurable: false
});
obj.id = 456; // 无效
delete obj.id; // 无效
3.2 隐藏属性
通过设置 enumerable
为 false
,可以隐藏属性,使其不出现在 for...in
循环或 Object.keys()
中。
Object.defineProperty(obj, 'secret', {
value: 'hidden',
enumerable: false
});
console.log(Object.keys(obj)); // 输出: ['name']
3.3 创建计算属性
使用 get
和 set
方法可以创建计算属性,动态获取或设置值。
const person = {
firstName: 'John',
lastName: 'Doe'
};
Object.defineProperty(person, 'fullName', {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(value) {
[this.firstName, this.lastName] = value.split(' ');
}
});
console.log(person.fullName); // 输出: John Doe
person.fullName = 'Jane Smith';
console.log(person.firstName); // 输出: Jane
console.log(person.lastName); // 输出: Smith
3.4 框架和库中的元编程
许多框架和库(如 Vue.js)使用属性描述符实现数据绑定和响应式系统。
const data = {};
Object.defineProperty(data, 'message', {
get() {
return this._message;
},
set(value) {
this._message = value;
console.log('Message updated:', value);
}
});
data.message = 'Hello, World!'; // 输出: Message updated: Hello, World!
3.5 在类中使用属性描述符
在类中,属性描述符可以用于限制属性的修改或实现只读属性。
class Goods {
constructor(goods) {
// 克隆并冻结原始对象,防止修改
goods = { ...goods };
Object.freeze(goods);
// 定义只读的 data 属性
Object.defineProperty(this, 'data', {
get() {
return goods;
},
set(value) {
throw new Error('data 是只读的');
},
configurable: false
});
// 定义可写的 name 属性
let internalGoodsName = '';
Object.defineProperty(this, 'name', {
get() {
return internalGoodsName;
},
set(value) {
internalGoodsName = value;
}
});
// 定义计算属性 totalPrice
Object.defineProperty(this, 'totalPrice', {
get() {
return this.data.price * this.data.num;
}
});
// 密封对象,防止新增属性
Object.seal(this);
}
}
// 冻结原型,防止修改
Object.freeze(Goods.prototype);
const goods = new Goods({
name: '手机',
price: 3000,
num: 3
});
console.log(goods.totalPrice); // 输出: 9000
4. 总结
属性描述符为 JavaScript 对象属性提供了精细的控制能力,适用于多种场景,如保护属性不被修改、隐藏属性、创建计算属性等。在现代开发中,属性描述符广泛应用于框架和库中,用于实现数据绑定、响应式系统等高级功能。