1. 程式人生 > >JavaScript.descriptor(屬性描述符)

JavaScript.descriptor(屬性描述符)

屬性描述符是對JavaScript屬性的描述,包括:value、writable、enumerable、configurable,除value其他預設為true。


本文包括:

  • 取得屬性描述符、 Object.getOwnPropertyDescriptor( obj, "property-name" );

 

  • 屬性描述符詳解、

    1. writable[物件是否可以再賦值], enumerable[物件是否可以迭代], configurable[是否可以通過Object.defineProperty對物件再次配置]

 

  • 屬性描述符應用、 writable: false  &&  configurable: false 產生物件常量

 

  • 其他相關:

 

  1. 禁止擴充套件:Object.preventExtensions(obj),阻止物件再新增屬性,物件不可以擴充套件。
  2. 封裝: 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

原文