ES5的Object中有一個方法:Object.defineProperty,這個方法可以直接在一個物件上定義一個新屬性,或者修改一個物件的現有屬性,並返回這個物件(摘自MDN)。
1.基本語法
Object.defineProperty(obj, prop, descriptor)
複製程式碼
其中:
obj: (必需, Object) 即將在其上定義屬性的目標物件
prop: (必需, String) 即將定義(或修改)的屬性的名稱
descriptor: (必需, Object) 即將被定義(或修改)的屬性的描述符
複製程式碼
前兩個引數好理解,主要是第三個引數比較麻煩。在分析第三個引數前,先舉一個例子:
let Product = {};
Object.defineProperty(Product, "discount", {
// 對discount屬性的描述
})
複製程式碼
在上面的程式碼中,我建立了一個Product物件,併為其新增了一個discount屬性,而第三個引數則是對該屬性的描述.
接下來我們要詳細分析一下descriptor引數,即屬性的描述符。
2.屬性描述符
屬性描述符可以有兩種形式:資料描述符和存取描述符,這兩種形式的鍵值有的相同,有的不同,具體如下:
2.1 公共鍵值
configurable
複製程式碼
當且僅當該屬性的configurable為true時,該屬性描述符才能夠被改變,同時該屬性也能從對應的物件上被刪除。預設為false。
enumerable
複製程式碼
當且僅當該屬性的enumerable為true時,該屬性才能夠出現在物件的列舉屬性中。預設為 false。
2.2 資料描述符的可選鍵值
value
複製程式碼
該屬性對應的值。可以是任何有效的JavaScript值(數值,物件,函式等)。預設為undefined。
writable
複製程式碼
當且僅當該屬性的writable為true時,value才能被賦值運算子改變。預設為false。
2.3 存取描述符的可選鍵值
get
複製程式碼
一個給屬性提供 getter 的方法,如果沒有 getter 則為 undefined。當訪問該屬性時,該方法會被執行,方法執行時沒有引數傳入,但是會傳入this物件(由於繼承關係,這裡的this並不一定是定義該屬性的物件)。 預設為 undefined。
set
複製程式碼
一個給屬性提供 setter 的方法,如果沒有 setter 則為 undefined。當屬性值修改時,觸發執行該方法。該方法將接受唯一引數,即該屬性新的引數值。 預設為 undefined。
綜上,現在我可以通過資料描述符為物件新增一個屬性:
let Product = {};
Object.defineProperty(Product, "discount", {
value: 20,
writable: true,
configurable: true,
enumerable: true
})
複製程式碼
也可以通過存取描述符為物件新增屬性:
let Product = {},
value = 1;
Object.defineProperty(Product, "discount", {
get: function () {
return value;
},
set: function (newValue) {
value = newValue;
},
configurable: true,
enumerable: true
})
複製程式碼
此外,一定要注意:屬性描述符可以是資料或存取描述符的其中一種,但是千萬不能混用。比如這樣:
let Product = {};
Object.defineProperty(Product, "discount", {
value: 20,
writable: true,
// get不能與value,writable同時使用!!
get: function () {
return 20;
},
configurable: true,
enumerable: true
})
複製程式碼
這是錯誤的!
3.相容性
IE8以下是不相容的。
參考資料: