在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
來添加屬性。