对象的属性描述(Property Descriptor)
参考文章:
- https://juejin.im/post/5b97903de51d450e3d2ca94c
- https://www.zhihu.com/question/40648241/answer/135240926
使用 Object.getOwnPropertyDescriptor
方法获取属性的描述:
let person = {name: 'tom', age: 16};
let descriptor = Object.getOwnPropertyDescriptor(person, 'name');
console.log(descriptor );
结果:
{
value: "tom",
writable: true,
enumerable: true,
configurable: true
}
使用 Object.getOwnPropertyDescriptors
方法获取全部属性的描述:
let person = {name: 'tom', age: 16};
let descriptor = Object.getOwnPropertyDescriptors(person);
console.log(descriptor );
结果:
{
age: {value: 16, writable: true, enumerable: true, configurable: true}
name: {value: "tom", writable: true, enumerable: true, configurable: true}
}
数据属性(Data Properties)
- configurable(可配置性)
可配置性决定是否可以使用 delete
删除属性,以及是否可以修改属性描述符的特性,默认 true
。
设置为 false
后无法使用 delete
删除属性,严格模式下直接报错;并且不能使用 defineProperty()
方法来修改属性描述符,但可以用使用 defineProperty()
方法将 writable
的状态从 true
改为 false
(只有这一种情况可以修改);var
声明变量时默认为 false
。
例子:
let person = {name: 'tom', age: 16};
Object.defineProperty(person, 'name', {configurable: false});
delete person.name;
console.log(person)
// {name: "tom", age: 16}
可见 name
属性并未被删除。
- enumerable(可枚举性)
可枚举性决定属性是否出现在对象的属性枚举中。
用户定义的普通属性默认是可枚举的,而原生继承的属性默认是不可枚举的。
使用 propertyIsEnumerable()
可以判断对象的属性是否可枚举:
let person = {name: 'tom', age: 16};
person.propertyIsEnumerable('name')
// true
我们修改一下 name
属性的 enumerable
再看看:
Object.defineProperty(person, 'name', {enumerable: false})
person.propertyIsEnumerable('name')
false
具体来说,enumerable
属性会影响到:
-
fon in
循环是否能遍历到该属性 -
Object.keys
方法是否能取到该属性 -
JSON.stringify
方法是否能取到该属性
- value (属性值)
属性值包含这个属性的数据值,读取属性值的时候,从这个位置读,写入属性值的时候,把新值保存在这个位置。默认 undefined
。
- writable (可写性)
可写性决定是否可以修改属性的值,默认为 true
;设置为 false
后赋值语句会静默失败,严格模式赋值直接报错。
通过 Object.defineProperty()
方法改变属性 value
的值不会受影响,因为这也意味着在重置 writable
的属性值为 false
。
看一个例子,name
属性没有被修改:
let person = {name: 'tom', age: 16};
Object.defineProperty(person, 'name', {writable: false})
person.name = 'john'
console.log(person)
// {name: "tom", age: 16}
访问器属性(Accessor Properties)
访问器属性不包含数据值,它们包含一对儿 getter
和 setter
函数(不过,这两个函数都不是必需的)。
在读取访问器属性时,会调用 getter
函数,在写入访问器属性时,又会调用 setter
函数并传入新值。
例子:
let person = {name: 'tom', _age: 16};
Object.defineProperty(person, 'age', {
get: function() {
return this._age;
},
set: function(newValue) {
this._age = newValue;
}
})
person.age = 18;
console.log(person.age)
// 18
这里我们为 _age
属性设定了 get
和 set
的访问器属性。