理解Object.defineProperty()

龍恩0707發表於2017-09-01

理解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

相關文章