ES5中对象的属性可以分为数据属性和访问器属性
- 数据属性
数据属性包含以下4个特性:
[[configurable]]:表示属性是否可以被delete,以及其他3个属性描述符的值是否可以被修改,甚至改写成访问器属性(Vue的ObServer就是这样进行数据劫持的)
[[enumerable]]:是否可枚举,是否能通过for in 循环返回该属性
[[writable]]: 是否可修改
[[value]]:属性的数据值,默认是undefined
数据属性可以通过字面量形式直接定义(包括obj.proper),或者通过Object.defineProperty(obj)来定义,如:
var obj = {
_name: 'zyp',
_age: 18,
}
Object.defineProperty(obj, 'like', {
value: 'sleep'
})
用Object.getOwnPropertyDescriptors(obj)可以获取对象的所有属性,包括属性的特性。
var propers = Object.getOwnPropertyDescriptors(obj)
console.log('propers', propers)
输出的结果见下图,我们可以看到:通过字面量直接定义的数据属性的[[configurable]]、[[enumerable]]、[[value]]三个特性值均默认为true;通过defineProperty()定义的数据属性的[[configurable]]、[[enumerable]]、[[value]]三个特性值均默认为false。
2. 访问器属性(ie9+支持)
访问器属性包含以下4个特性:
[[configurable]]:表示属性是否可以被delete,以及其他3个属性描述符的值是否可以被修改,甚至改写成数据属性。
[[enumerable]]:是否可枚举,是否能通过for in 循环返回该属性
[[set]]:设置属性值是访问的函数。默认是undefined
[[get]]:读取属性值是访问的函数。默认是undefined
访问器属性只能通过Object.defineProperty(obj)来进行定义,如:
Object.defineProperty(obj, 'name', {
get: function() {
return this._name
},
set: function(newVal) {
this._name = newVal
}
})
var propers = Object.getOwnPropertyDescriptors(obj)
console.log('propers', propers)
同样,通过defineProperty()函数定义的访问器属性的[[configurable]]、[[enumerable]]两个特性值均默认为false,如图:
如果只定义了set特性或者只定义了get特性
Object.defineProperty(obj, 'age', {
set: function(newVal) {
this._age = newVal
}
})
var propers = Object.getOwnPropertyDescriptors(obj)
console.log('propers', propers)
var age = obj.age //得到的age值为undefined
因此,在非严格模式下,如果只定义了set特性,那么获取得到该访问器属性的值为undefined, 严格模式下会报错(高程上是这么说的,但是实际在chrome控制台中用’use strict’并没有抛出错误)。
接下来对数据属性和访问器属性共有的configurable特性进行研究:
针对obj中的数据属性_age和_name
- _age属性的configurable特性值为true,我们可以对其enumerable、writable、 value三个特性进行修改。
Object.defineProperty(obj, '_age', {
enumerable: false,
writable: false,
value: 19
})
var propers = Object.getOwnPropertyDescriptors(obj)
console.log('propers', propers)
也可以将其修改为访问器属性,或者直接delete该属性,这里只演示delete操作。
delete obj._age
var propers = Object.getOwnPropertyDescriptors(obj)
console.log('propers', propers)
- 我们将_name的configurable属性为false后,我们只能将writable特性修改为false,不能修改其他特性,否则会报错。
Object.defineProperty(obj, '_name', {
configurable: false
})
Object.defineProperty(obj, '_name', {
writable: false
}) //不报错
Object.defineProperty(obj, '_name', {
value: 'zyp1'
})
也不能进行delete操作(无效)。
delete obj._name
注意:数据属性的特性和访问器属性的特性不能同时存在于一个属性中。
参考:JavaScript高级程序设计(第3版) 6.1.1