在JavaScript中,属性描述符是ECMAScript 5引入的一个重要概念,它允许我们更精细地控制对象属性的行为。通过属性描述符,我们可以定义属性的值、是否可写、是否可枚举、是否可配置等特性。
一、什么是属性描述符?
属性描述符是一个内部对象,用来描述对象属性的特性。在JavaScript中,对象的属性可以分为两种:
- 数据属性:它的本质就是一个数据值。
- 存取器属性:它的本质是一个函数,但可以像普通属性一样使用。当给该属性赋值时,会运行相应的
setter
函数;当获取该属性的值时,会运行相应的getter
函数。
属性描述符一共有6个,可以选择使用:
value
:设置属性值,默认值为undefined
。writable
:设置属性值是否可写,默认值为false
。enumerable
:设置属性是否可枚举,即是否允许使用for/in
语句或Object.keys()
函数遍历访问,默认为false
。configurable
:当设置为false
时,该属性的类型不能在数据属性和访问器属性之间更改,且该属性不可被删除,且其描述符的其他属性也不能被更改(但是,如果它是一个可写的数据描述符,则value
可以被更改,writable
可以更改为false
)。默认值为false
。get
:取值函数,默认为undefined
。set
:存值函数,默认为undefined
。
需要注意的是,get
和set
以及value
和writable
这两组是互斥的。设置了get
和set
就不能设置value
和writable
,反之亦然。
二、操作属性描述符
(一)Object.getOwnPropertyDescriptor()
该方法用于获取指定对象的属性描述符。
var obj = {};
Object.defineProperty(obj, 'x', { value: 100 });
console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
// { value: 100, writable: false, enumerable: false, configurable: false }
(二)Object.defineProperty()
该方法用于定义或修改一个属性的描述符。
var obj = {};
Object.defineProperty(obj, 'x', {
value: 1,
writable: false
});
obj.x = 2;
console.log(obj.x); // 1
(三)Object.defineProperties()
该方法用于同时定义多个属性的描述符。
var obj = {};
Object.defineProperties(obj, {
x: {
value: 1,
writable: false
},
y: {
value: 2,
writable: true
}
});
console.log(obj.x); // 1
console.log(obj.y); // 2
(四)Object.getOwnPropertyNames()
该方法用于获取对象的所有私有属性。
var obj = { x: 1, y: 2 };
console.log(Object.getOwnPropertyNames(obj)); // ['x', 'y']
(五)Object.keys()
该方法用于获取对象的所有本地可枚举的属性。
var obj = { x: 1, y: 2 };
console.log(Object.keys(obj)); // ['x', 'y']
(六)propertyIsEnumerable()
该方法用于判断指定的属性是否可枚举。
var obj = { x: 1, y: 2 };
console.log(obj.propertyIsEnumerable('x')); // true
console.log(obj.propertyIsEnumerable('y')); // true
三、控制对象状态
(一)Object.preventExtensions()
该方法用于阻止为对象添加新的属性。
var obj = {};
Object.preventExtensions(obj);
obj.z = 3;
console.log(obj.z); // undefined
(二)Object.seal()
该方法用于阻止为对象添加新的属性,同时也无法删除旧属性。等价于将属性描述符的configurable
属性设为false
。
var obj = { x: 1 };
Object.seal(obj);
delete obj.x;
console.log(obj.x); // 1
(三)Object.freeze()
该方法用于阻止为一个对象添加新属性、删除旧属性、修改属性值。
var obj = { x: 1 };
Object.freeze(obj);
obj.x = 2;
console.log(obj.x); // 1
四、应用场景
(一)数据属性
var obj = {};
Object.defineProperty(obj, 'x', { value: 100 });
console.log(obj.x); // 100
(二)存取器属性
var obj = {
_x: 1,
get x() { return this._x },
set x(value) {
if (typeof value != "number") {
throw new Error('请输入数字');
}
this._x = value;
}
};
console.log(obj.x); // 1
obj.x = 2;
console.log(obj.x); // 2
(五)控制对象状态
var obj = { x: 1 };
Object.preventExtensions(obj);
console.log(Object.isExtensible(obj)); // false
Object.seal(obj);
console.log(Object.isSealed(obj)); // true
Object.freeze(obj);
console.log(Object.isFrozen(obj)); // true
五、总结
在实际开发中,合理使用属性描述符可以提升代码的可维护性和安全性。希望本文能帮助你更好地理解和应用属性描述符。