Object 的属性描述符
在 JavaScript 中, 对象(Object
)可以看作是属性(property
)的集合,属性是 key:value
的形式。key
可以是字符串也可以是 Symbol
,value
可以是任何类型(包括其它对象)。
对象的每个属性(property
)都有对应的 attributes
(标志),由于 attributes
是在 JavaScript
引擎内部使用的,所以我们并不能直接访问到它们。为了区分两者,通常情况下 [property]
是用单方括号,[[attribute]]
是用双方括号。
有一部分特殊的 attributes
是 property
的描述符,我们可以在 Object.defineProperty()
方法中直观地看到,此方法允许我们精准地添加或修改对象的属性及其描述符。
Object.defineProperty()
静态方法 Object.defineProperty()
可以在对象上定义新的属性,也可以修改已有的属性,它会返回本对象。
格式:Object.defineProperty(obj, prop, descriptor)
两种描述符
对象中的属性描述符有两种形式:数据描述符
和访问器描述符
。数据描述符
是具有值
的属性(可写或不可写),访问器描述符
是由一对 getter-setter
函数描述的属性。
data descriptors
accessor descriptors
属性描述符要么是数据描述符,要么是访问器描述符,不能两者兼而有之。
数据描述符
和访问器描述符
都是对象
,即 key:value
的集合,它们都有下面的两个 key:
enumerable
布尔类型。当且仅当在枚举对象的属性列表时,该属性需要被显示出来的时候,才会被置为 true。configurable
布尔类型。如果可以更改该属性的描述符类型(数据描述符 or 访问器描述符),且可以在对象上删除该属性的时候,就置为 true。
数据描述符
还可以有以下 key:
value
与属性关联的值,可以是任何有效的JavaScript
值。writable
布尔类型。如果可以使用赋值运算符来修改该属性的value
,那就置为true
。
访问器描述符
还可以有以下 key:
get
用作属性的getter
函数,如果没有则为undefined
。当访问该属性的值时,就会调用此函数(不带参数),并将 this 设置为访问该属性的对象,返回值将被用作是该属性的值。set
用作属性的setter
函数,如果没有则为undefined
。当设置(assign)该属性的值时,就会调用此函数(带一个参数,即分配给属性的值),并将 this 设置为给该属性分配值的对象。
如果描述符既没有value, writable
也没有get, set
,就会将其视为数据描述符
。如果描述符既有 value/writable 也有 get/set,则会抛出异常。
注意:这些 attributes
不一定是描述符自身的 properties
,也可能是继承来的 properties
。所以保险起见,要么使用 Object.create(null)
让描述符指向 null
,要么使用对象字面量来显式指定描述符的值。如下:
//todo
// 1. Object.create(null)
let obj = {
};
let descriptor = Object.create(null); // no inherited properties
descriptor.value = 'static';
Object.defineProperty(obj, 'key1', descriptor);
// 2. 用对象字面量,显式指定
Object.defineProperty(obj, 'key2', {
enumerable: false,
configurable: false,
writable: false,
value: 'static'
});
默认值
用 Object.defineProperty()
定义的描述符的默认值分别是:
enumerable
,configurable
,writable
均默认是false
value
,get
,set
均默认是undefined
也就是说,通过此方法添加的属性,默认是不可枚举、不可变的。而通过赋值添加的普通属性,默认是可枚举、可删除可修改的。
let person = {
name: "David"
};
person.age = 34;
Object.defineProperty(person, "sex", {
value: "male" });
console.log(Object.getOwnPropertyDescriptors(person)); // 详见下方截图
以上代码,运行结果如下:
{
name: {
value: 'David',
writable: true,
enumerable: true,
configurable: true