在ES5开始,全部属性都具有了属性描述符。
咱们能够经过Object.getOwnPropertyDescriptor
来观察到属性的描述符,它是长这样子的。app
Object.getOwnPropertyDescriptor({a: 1}, 'a'); // { // value: 1, // writable: true, // enumerable: true, // configurable: true // }
writable
决定该属性是否只读。enumerable
决定该属性是否可枚举。configurable
决定该属性是否可从新设置描述符。this
当属性的configurable
为true时,咱们能够经过Object.defineProperty
来修改属性描述符。code
'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 '#<Object>' for(var i in foo) {console.log(i)}; // 'nothing happend' Object.defineProperty(foo, 'a', { // Uncaught TypeError: Cannot redefine property: a configurable: true });
getter和setter有两种方式定义对象
字面量定义ip
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
的描述符。get
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
)时,严格模式下会抛出异常,非严格模式下,这条赋值语句会被忽略。这种属性称为 屏蔽属性。
举个例子it
'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 '#<Object>'
还有一种状况console
当你给一个对象赋值一个新的属性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
来添加属性。