属性描述符
在ES5开始,所有属性都具备了属性描述符。
我们可以通过Object.getOwnPropertyDescriptor
来观察到属性的描述符,它是长这样子的。
Object.getOwnPropertyDescriptor({a: 1}, 'a');
// {
// value: 1,
// writable: true,
// enumerable: true,
// configurable: true
// }
writable
决定该属性是否只读。enumerable
决定该属性是否可枚举。configurable
决定该属性是否可重新设置描述符。
属性描述符的设置
当属性的configurable
为true时,我们可以通过Object.defineProperty
来修改属性描述符。
'use strict';
var foo = {a: 1};
for(var i in foo) {console.log(i)};
// 'a'
Object.defineProperty(foo, 'a', {
writable: false,
enumerable: false,
configurable: false
});
foo.a = 2;// Uncaught TypeError: Cannot assign to read only property 'a' of object '#
访问描述符(getter和setter)
getter和setter有两种方式定义
字面量定义
var foo = {
get a(){
return this._a;
},
set a(value){
this._a = value;
}
};
使用Object.defineProperty
定义
var foo = {a: 1};
Object.defineProperty(
foo,
'a',
{
get(){
return this._a;
},
set(value){
this._a = value;
}
}
);
这个时候再看看属性a
的描述符。
Object.getOwnPropertyDescriptor(foo, 'a')
// {
// get: ƒ a(),
// set: ƒ a(value),
// enumerable: true,
// configurable: true
// }
当出现getter
或setter
时,value
和writable
就会失效。
此时,属性a
的描述符被称为访问描述符。
访问描述符和属性描述符互斥,如果此时再重新设置value
或者writable
描述符,setter
和getter
也会被丢弃。
屏蔽属性
当你给一个对象赋值一个新的属性foo
时,如果该对象的原型链上已存在属性foo
,并且foo
被标记为只读(writable: false
)时,严格模式下会抛出异常,非严格模式下,这条赋值语句会被忽略。这种属性称为 屏蔽属性。
举个例子
'use strict';
var anotherObject = {};
Object.defineProperty(anotherObject, 'foo', {// 将anotherObject的foo属性设为只读
value: 1,
writable: false
});
var myObject = Object.create(anotherObject);// 将myObject的原型设置为anotherObject
console.log(myObject);// {}
console.log(myObject.foo);// 1
myObject.foo = 2;// Uncaught TypeError: Cannot assign to read only property 'a' of object '#
还有一种情况
当你给一个对象赋值一个新的属性foo
时,如果该对象的原型链上已存在属性foo
,并且foo
被设置了setter
时,将会调用这个setter
,并且该赋值语句将会被忽略,此时也会发生属性屏蔽。
var anotherObject = {};
Object.defineProperty(anotherObject, 'foo', {// 给anotherObject的foo属性设置setter
set(value) {
console.log(value);
this._foo = value;
},
get() {
return this._foo;
}
});
var myObject = Object.create(anotherObject);// 将myObject的原型设置为anotherObject
myObject.foo = 2;// 此时会触发anotherObject.foo的setter,控制台输出2
console.log(Object.hasOwnProperty(myObject, 'foo'));// false
解决方案
使用Object.defineProperty
来添加属性。