理解Object.defineProperty()
Object.defineProperty() 方法直接在一個物件上定義一個新屬性,或者修改一個已經存在的屬性, 並返回這個物件。
基本語法:Object.defineProperty(obj, prop, descriptor)
@param obj 【必須】目標物件
@param prop【必須】新增或修改的屬性名字
@param descriptor 屬性描述符。
屬性描述符 包括兩種形式:資料描述符和存取描述符。資料描述符是一個擁有可寫或不可寫值的屬性。存取描述符是由一對getter-setter函式功能來描述的屬性。
但是該兩者不能同時存在,描述符只能是其中之一。
一:資料描述符:
比如如下一個普通物件:
var obj = { "name": "kongzhi" };
資料描述符屬性如下:
Object.defineProperty(obj, "name", { configurable: true | false, enumerable: true | false, value: '任意型別的值', writable: true | false });
下面我們來理解下每個屬性的含義:
1. value:
含義: 屬性的值,可以是任何型別的值,預設為undefined
1-1 不設定value屬性
如下程式碼:
var obj = {}; Object.defineProperty(obj, "name", {}); console.log(obj.name); // undefined
1-2 設定value屬性
// 設定value 程式碼如下: var obj = {}; Object.defineProperty(obj, "name", { value: "kongzhi" }); console.log(obj.name); // kongzhi
2. writable
含義:屬性的值是否可以被重寫,true: 可以被重寫,false: 不能被重寫。預設為false。
2-1 writable設定為false,不能重寫,如下程式碼:
var obj = {}; Object.defineProperty(obj, "name", { value: "kongzhi", writable: false }); // 先列印下值 console.log(obj.name); // kongzhi // 更改值 obj.name = "longen"; // 再列印下 console.log(obj.name); // kongzhi
2-2 writable設定為true,可以被重寫,如下程式碼:
var obj = {}; Object.defineProperty(obj, "name", { value: "kongzhi", writable: true }); // 先列印下值 console.log(obj.name); // kongzhi // 更改值 obj.name = "longen"; // 再列印下 console.log(obj.name); // longen
3. enumerable
含義:該屬性是否可以被列舉(如:for..in 或 Object.keys()). 如果為true的話,可以被列舉,設定為false的話,不能被列舉,預設為false。
3-1 enumerable被設定為false,不能被列舉,如下程式碼:
var obj = {}; Object.defineProperty(obj, "name", { value: "kongzhi", writable: false, enumerable: false }); // 先列印物件一下看看 console.log(obj); // {name: "kongzhi"} // 再列舉物件的屬性 for(var attr in obj) { console.log(attr); // 什麼都沒有輸出 說明不能被列舉 }
3-2 enumerable 設定為true,可以被列舉,如下程式碼:
var obj = {}; Object.defineProperty(obj, "name", { value: "kongzhi", writable: false, enumerable: true }); // 先列印物件一下看看 console.log(obj); // {name: "kongzhi"} // 再列舉物件的屬性 for(var attr in obj) { console.log(attr); // 輸出 name }
4. configurable
含義:是否可以刪除目標屬性或是否可以修改目標屬性的特性。如果為true的話,可以被刪除或可以修改屬性,為false的話,不能刪除目標屬性或不能修改目標屬性,預設為false
4-1 configurable: false, 為false的話,不能刪除目標屬性或不能修改目標屬性。如下程式碼:
var obj = {}; Object.defineProperty(obj, "name", { value: "kongzhi", writable: false, enumerable: false, configurable: false }); // 先列印物件一下看看 console.log(obj); // {name: "kongzhi"} // 刪除屬性 delete obj.name; // 重新列印下物件,看是否刪除成功了 console.log(obj.name); // kongzhi // 修改屬性 obj.name = "longen"; // 重新列印下物件,看是否修改成功了 console.log(obj.name); // kongzhi
4-2 configurable: true, 可以刪除目標屬性 或 可以修改目標屬性,如下程式碼:
var obj = {}; Object.defineProperty(obj, "name", { value: "kongzhi", writable: false, enumerable: false, configurable: true }); // 先列印物件一下看看 console.log(obj); // {name: "kongzhi"} // 刪除屬性 delete obj.name; // 重新列印下物件,看是否刪除成功了 console.log(obj.name); // undefined // 修改屬性 obj.name = "longen"; // 重新列印下物件,看是否修改成功了 console.log(obj.name); // longen
二: 存取器描述
使用存取器描述屬性的時候,可以使用如下屬性:
var obj = {}; Object.defineProperty(obj, "name", { enumerable: true | false, configurable: true | false, get: function() {} | undefined, set: function(value) {} | undefined });
注意:當使用了getter或setter的時候,就不能使用writable和value這兩個屬性。否則會報錯。
getter 是獲取屬性值的方法。如果沒有getter 則預設為 undefined,當我們讀取某個屬性的時候,其實是在物件內部呼叫了該方法,該方法必須使用return語句,返回值被作為屬性值。
setter 是設定屬性的方法。如果沒有setter,則預設為undefined,該方法接收一個引數,並將該引數值分配該屬性。當我們設定某個屬性的時候,實際上在物件的內部呼叫了該方法。
如下程式碼是使用getter和setter的程式碼:
var obj = {}; var initValue = "kongzhi"; Object.defineProperty(obj, "name", { get: function() { // 當獲取屬性值的時候觸發的函式 return initValue; } , set: function(value) { // 當設定值的時候觸發的函式 initValue = value; } }); // 獲取值 console.log(obj.name); // kongzhi // 設定值 obj.name = "longen"; // 列印下 console.log(obj.name); // longen