JavaScript.descriptor(屬性描述符)
阿新 • • 發佈:2018-11-15
屬性描述符是對JavaScript屬性的描述,包括:value、writable、enumerable、configurable,除value其他預設為true。
本文包括:
- 取得屬性描述符、 Object.getOwnPropertyDescriptor( obj, "property-name" );
- 屬性描述符詳解、
1. writable[物件是否可以再賦值], enumerable[物件是否可以迭代], configurable[是否可以通過Object.defineProperty對物件再次配置]
- 屬性描述符應用、 writable: false && configurable: false 產生物件常量
- 其他相關:
- 禁止擴充套件:Object.preventExtensions(obj),阻止物件再新增屬性,物件不可以擴充套件。
- 封裝: Object.seal(obj),封裝一個物件,物件上不能再新增新的屬性、不能重新定義屬性描述符、不能刪除某個屬性,
等價於 Object.preventExtensions(obj),並設定現有的所有屬性為 configurable:false。
3.凍結:Object.freeze(obj),物件不能再做任何修改或者刪除屬性的操作,
效果相當於呼叫了 Object.seal(obj) 並設定所有屬性為 writable: false
1.取得屬性描述符
var myObject = { a: 2 }; Object.getOwnPropertyDescriptor( myObject, "a" ); // { value: 2, writable: true, enumerable: true, configurable: true }
可以看到,物件myObject的屬性a,除了擁有value描述符,還擁有writable、enumerable、configurable三個用於描述屬性描述符。
var myObject = {}; Object.defineProperty( myObject,"a", { value: 2, writable: true, configurable: true, enumerable: true } ); // 上面的定義等同於 myObject.a = 2; // 所以如果不需要修改這三個特性,我們不會用 `Object.defineProperty` myObject.a; // 2
通過Object.defineProperty(obj,"propertyname",{})可以為物件新增屬性,並且通過屬性描述符為屬性新增一些特性。
2.屬性描述符詳解
2.1 writable[物件是否可以再賦值]
// "use strict"; var myObject = {}; Object.defineProperty( myObject, "a", { value: 2, writable: false, // 不可寫! configurable: true, enumerable: true } ); myObject.a = 3; // 寫入的值將會被忽略 myObject.a; // 2 /* 如果應用了 strict mode 的話,那麼 myObject.a 將會丟擲 TypeError,而不是僅僅忽略寫入的值。
ES5 還引入了物件屬性的 Getter 和 Setter,這裡的 writable: false可以認為是和沒有定義或者定義了沒有任何操作的 setters 的情況大致等同。
當然了,如果是 strict mode 下,需要在 setters 裡面丟擲 TypeError 來完全模擬 writable: false 的情形。 */
2.2 enumerable[物件是否可以迭代]
var myObject = { a: 2 }; myObject.a = 3; myObject.a; // 3 Object.defineProperty( myObject, "a", { value: 4, writable: true, configurable: false, // 不可配置! enumerable: true } ); myObject.a; // 4 myObject.a = 5; myObject.a; // 5 Object.defineProperty( myObject, "a", { value: 6, writable: true, configurable: true, //同樣的,也不能用delete刪除物件這個屬性了 enumerable: true } ); // TypeError /* 注意,一旦某個屬性被指定為 configurable: false,
那麼就不能從新指定為configurable: true 了,這個操作是單向,不可逆的。 */
2.3 configurable[是否可以通過Object.defineProperty對物件再次配置]
var myObject = { }; Object.defineProperty( myObject, "a", // make `a` enumerable, as normal { enumerable: true, value: 2 } ); Object.defineProperty( myObject, "b", // make `b` NON-enumerable { enumerable: false, value: 3 } ); myObject.b; // 3 ("b" in myObject); // true myObject.hasOwnProperty( "b" ); // true // ....... for (var k in myObject) { console.log( k, myObject[k] ); } // "a" 2 myObject.propertyIsEnumerable( "a" ); // true myObject.propertyIsEnumerable( "b" ); // false Object.keys( myObject ); // ["a"] Object.getOwnPropertyNames( myObject ); // ["a", "b"] /* 這裡可以看到,enumerable: false 使得該屬性從物件屬性列舉操作中被隱藏, 但Object.hasOwnProperty(...) 仍然可以檢測到屬性的存在。 另外,Object.propertyIsEnumerable(..) 可以用來檢測某個屬性是否可列舉, Object.keys(...) 僅僅返回可列舉的屬性, 而Object.getOwnPropertyNames(...) 則返回該物件上的所有屬性, 包括不可列舉的。 */
3.屬性描述符應用
var myObject = {}; Object.defineProperty( myObject, "FAVORITE_NUMBER", { value: 42, writable: false, configurable: false } ); /* 通過組合 writable: false 和 configurable: false,可以建立一個不能修改、重新定義或刪除其屬性的物件常量 這裡對該物件屬性的刪除,修改操作會被忽略,不能再用Object.defineProperty(...) 來重新配置該屬性的特性 */
4.其他相關
4.1禁止擴充套件
/* 如果希望阻止新的屬性被加入到物件,可以通過呼叫 Object.preventExtensions(...) 來做到這一點: */ var myObject = { a: 2 }; Object.preventExtensions( myObject ); myObject.b = 3; myObject.b; // undefined //在 strict mode 下,行為稍有不同,對屬性的賦值會丟擲 TypeError, 而不是僅僅忽略賦值操作
4.2封裝
/* 可以通過 Object.seal(...) 來封裝一個物件。在呼叫這個操作之後, 物件上不能再新增新的屬性,也不能重新定義屬性描述符或者刪除某個屬性: */ var myObject = { a: 2 }; Object.seal(myObject); myObject.b = 'b'; console.log(myObject); // {a: 2} myObject.a = 6; console.log(myObject); // {a: 6} /* Object.seal(...) 相當於呼叫了 Object.preventExtensions(..),並設定現有的所有屬性為 configurable:false。 */
4.3凍結
/* 呼叫 Object.freeze(...) 可以建立一個被凍結的物件,這個物件擁有不能再被做任何修改或者刪除屬性的操作 */ var myObject = { a: 2 }; Object.seal(myObject); myObject.b = 'b'; console.log(myObject); // {a: 2} myObject.a = 6; console.log(myObject); // {a: 2} //相當於呼叫了 Object.seal(...) 並設定所有屬性為 writable: false