经常会看到一些技术文章说,可枚举不可枚举,一直很懵。其实就是对象属性描述符中的Enumerable(可枚举性)。下面来看看有哪些对象属性描述符~
描述符类型
分为两种
- 数据属性(data property)
包含一个数据值的位置,在这个位置可以读取和写入值,有四个特性
- 访问器属性(accessor poperty)
名字、值和一组属性描述符构成的。而属性值可以用一个或两个方法替代,这两个方法就是getter和setter
他们共同的特性
configurable(可配置性)
可配置性决定是否可以使用delete删除属性,以及是否可以修改属性描述符的特性,默认true;
设置为false后无法使用delete删除属性,严格模式下直接报错;并且不能使用defineProperty()方法来修改属性描述符,但可以用使用defineProperty()方法将writable的状态从true改为false(只有这一种情况可以修改);var声明变量时默认为false;
enumerable(可枚举性)
可枚举性决定属性是否出现在对象的属性枚举中。
用户定义的普通属性默认是可枚举的,而原生继承的属性默认是不可枚举的。
propertyIsEnumerable() 可以判断对象的属性是否可枚举
1
2
3
4
5
6var o = {a:1};
console.log(o.propertyIsEnumerable('a'))
//true
Object.defineProperty(o,'a',{enumerable:false})
console.log(o.propertyIsEnumerable('a'))
//false
具体来说,比如
- fon in 循环是否能遍历到该属性
- Object.keys方法是否能取到该属性
- JSON.stringify方法是否能取到该属性
不同的特性
数据属性 :
value (属性值)
属性值包含这个属性的数据值,读取属性值的时候,从这个位置读,写入属性值的时候,把新值保存在这个位置。默认undefined。
writable (可写性)
可鞋型决定是否可以修改属性的值,默认为true;设置为false后赋值语句会静默失败,严格模式赋值直接报错;
通过Object.defineProperty()方法改变属性value的值不会受影响,因为这也意味着在重置writable的属性值为false
访问器属性:
getter
在读取属性时调用的函数。默认undefined
setter
在写入属性时调用的函数。默认undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// getter 和 setter 取代了数据属性中的value和writable属性
// 只设置get方法没有set方法 对象的赋值会静默失败 严格模式下会报错
// 只设置set方法而不设置get方法 对象的属性值为undefined
// 所以一般都是成对出现的
var o ={
get a(){
return this._a;
},
set a(val){
this._a = val*2;
}
}
o.a = 1;
console.log(o.a);//2
// 可读可取
// 利用Object.defineProperty()对o的属性a的getter和setter进行配置
Object.defineProperty(o,'a',{
get: function(){
return this._a;
},
set :function(val){
this._a = val*2;
}
})
o.a = 1;
console.log(o.a);//2
描述符方法
Object.getOwnPropertyDescriptor()
第一个参数是该对象,第二个参数时对象的某一个属性。用于查询一个属性的描述符,并以对象的形式返回
1
2
3let obj = {holly: 'nice'}
console.log(Object.getOwnPropertyDescriptor(obj, 'holly'))
// {value: "nice", writable: true, enumerable: true, configurable: true}
Object.defineProperty()
第一个参数时对象,第二个参数是对象的某一个属性,第三个参数是要修改的配置;用于创建或配置对象的一个属性的描述符,返回配置后的对象(创建时,如果不针对描述符配置,则该项描述符默认false)
1
2
3
4
5
6
7
8
9let holly = {}
console.log(Object.defineProperty(holly, 'name', {
value: 'holly',
writable: true
}))
// {name: "holly"} 返回该对象
console.log(Object.getOwnPropertyDescriptor(holly, 'name'))
// {value: "holly", writable: true, enumerable: false, configurable: false}
// 由于没有配置 enumerable和configurable 为falseObject.defineProperties()
第一个参数是该对象,第二个是要修改的属性为键 特性为值组成的对象;用于创建或配置对象的多个属性的描述符,返回配置后的对象。
1
2
3
4
5
6
7
8
9
10
11
12
13let desc = {a: 1, b: 2}
console.log(Object.defineProperties(desc, {
a: {
value: 3,
enumerable: false
},
b: {writable: true}
}))
// {b: 2, a: 3}
console.log(console.log(Object.getOwnPropertyDescriptor(desc, 'a')))
// {value: 3, writable: true, enumerable: false, configurable: true}
console.log(Object.getOwnPropertyDescriptor(desc, 'b'))
// {value: 2, writable: true, enumerable: true, configurable: true}Object.create()
第一个参数指定原型,第二个参数属性和描述符对象;用于指定原型和属性来创建一个对象
1
2
3
4
5
6
7let newOne = Object.create(Object.prototype, {
a: {value: 'hello', enumerable: true}
})
console.log(newOne)
// {a: "hello"}
console.log(Object.getOwnPropertyDescriptor(newOne,'a'))
// {value: "hello", writable: false, enumerable: true, configurable: false}参考链接: https://www.cnblogs.com/xiaohuochai/p/5743821.html
应用场景
- 大部分是框架才会用到,比如Vue.js的双向数据绑定