1. 程式人生 > >詳解Object.defineProperty方法

詳解Object.defineProperty方法

Object.defineProperty() 方法會直接在一個物件上定義一個新屬性,或者修改一個物件的現有屬性, 並返回這個物件。參見Object.defineProperty語法。在vue.js是通過它實現雙向繫結的。俗稱屬性攔截器。

1、語法:

Object.defineProperty(obj, prop, descriptor)

引數說明:
// obj:必需。目標物件
// prop:必需。需定義或修改的屬性的名字
// descriptor:必需。目標屬性所擁有的特性

2、屬性描述符

所謂屬性描述符也就是Object.defineProperty(obj, prop, descriptor)方法裡的descriptor這個物件。
物件裡目前存在的屬性描述符有兩種主要形式:資料描述符和存取描述符。資料描述符是一個具有值的屬性,該值可能是可寫的,也可能不是可寫的。存取描述符是由getter-setter函式對描述的屬性。描述符必須是這兩種形式之一;不能同時是兩者。
是不是感覺有點迷惑,那我們來舉例說明:

(1)資料描述符

let obj = {}
Object.defineProperty(obj, "name", {
  enumerable: false,//是可選值,不選的話預設值為false,
  configurable: false,//是可選值,不選的話預設值為false,
  writable: false,
  value: "張三"
});

(2)存取描述符

let obj = {};
let newVal;
Object.defineProperty(obj, "name", {
  enumerable: false,//是可選值,不選的話預設值為false,
  configurable: false,//是可選值,不選的話預設值為false,
  get : function(){
    return newVal;
  },
  set : function(newValue){
    newVal= newValue;
  },
});

對比上面的2個例子,看出來資料描述符和存取描述符的區別了嗎?
答案:**存取描述符有set和get函式,但是不存在 writable和value這2個屬性**

描述符的值存在情況

3、描述符引數例項說明

configurable
當且僅當該屬性的 configurable 為 true 時,該屬性描述符才能夠被改變,同時該屬性也能從對應的物件上被刪除。預設為 false。

這個屬性起到兩個作用:
(1)、目標屬性是否可以使用delete刪除
(2)、目標屬性是否可以再次設定特性

//-----------------測試目標屬性是否能被刪除------------------------

//configurable為 false的情況,
let obj = {}
Object.defineProperty(obj, "name", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: "張三"
});
//刪除屬性
delete obj.newKey;
console.log( obj.name); //張三
也就是說 configurable: false的情況,我們沒有刪除物件屬性,
自己動手試試configurable: true的情況,打出來的值應該是undefined

//-----------------測試是否可以再次修改特性------------------------
let obj = {}
Object.defineProperty(obj, "name", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: "張三"
});
Object.defineProperty(obj, "name", {
  enumerable: true,
  configurable: true,
  writable: true,
  value: "李四李四"
});
console.log( obj.name); //報錯,"TypeError: Cannot redefine property: name"
也就是說第一個configurable設定為false的情況下,下邊的在從新設定物件屬性‘name’的時候會報錯。
4個屬性裡只要有一個值不一樣就會報錯。
當然瞭如果第一個configurable設定為true的情況,下邊就可以打印出 `李四李四`。

//-----------------2次設定的物件name一樣的情況下------------------------
let obj = {}
Object.defineProperty(obj, "name", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: "張三"
});
Object.defineProperty(obj, "name", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: "張三"
});
這個是不會報錯的,因為2次設定的屬性name的4個特性值都是一樣的,也就等於我們沒有修改描述符的值。

enumerable
當且僅當該屬性的enumerable為true時,該屬性才能夠出現在物件的列舉屬性中。預設為 false。

let obj = {}
Object.defineProperty(obj, "name", {
  enumerable: false,
  configurable: false,
  writable: false,
  value: "張三"
});
for(let attr in obj){
   console.log(attr) //undefined,因為我們設定了enumerable: false,
}
如果我們設定了enumerable: true會打印出值“name”。

value
該屬性對應的值。可以是任何有效的 JavaScript 值(數值,物件,函式等)。預設為 undefined。

//第一種情況:不設定value屬性
let obj = {}
Object.defineProperty(obj, "name", {
 
});
console.log(obj .name)//undefined

//第二種情況:設定value屬性
let obj = {}
Object.defineProperty(obj, "name", {
   value:'張三'
});
console.log(obj .name)//張三

writable
當且僅當該屬性的writable為true時,value才能被賦值運算子改變。預設為 false。

//第一種情況:設定writable屬性為false
let obj = {}
Object.defineProperty(obj, "name", {
   writable:false,
   value:"張三"
});
obj.name="李四"
console.log(obj.name)//張三

//第二種情況:設定writable屬性為true
let obj = {}
Object.defineProperty(obj, "name", {
   writable:true,
   value:"張三"
});
obj.name="李四"
console.log(obj.name)//李四

get
一個給屬性提供 getter 的方法,如果沒有 getter 則為 undefined。當訪問該屬性時,該方法會被執行,方法執行時沒有引數傳入,但是會傳入this物件(由於繼承關係,這裡的this並不一定是定義該屬性的物件)。 預設為 undefined。
set
一個給屬性提供 setter 的方法,如果沒有 setter 則為 undefined。當屬性值修改時,觸發執行該方法。該方法將接受唯一引數,即該屬性新的引數值。 預設為 undefined。

這2個方法是存取器描述符裡面的,示例如下:

var obj = {};
Object.defineProperty(obj,"name",{
    get:function (){} | undefined,
    set:function (value){} | undefined
    configurable: true | false
    enumerable: true | false
});

getter 是一種獲得屬性值的方法
setter是一種設定屬性值的方法。

let obj = {};
let name = '張三';
Object.defineProperty(obj,"name",{
    get:function (){
        //當獲取值的時候觸發的函式
        return name ;    
    },
    set:function (value){
        //當設定值的時候觸發的函式,設定的新值通過引數value拿到
        name = value;
    }
});
console.log(obj.name)//張三,
obj.name是獲取值,會走get函式

obj.name = "李四" // 這時是賦值,會走set函式,
console.log(obj.name) //李四

需要注意的是:get或set不是必須成對出現,任寫其一就可以。如果不設定方法,則get和set的預設值為undefined

關於Object.defineProperty方法大致也就這些了吧。

友情提示:vue.js是通過Object.defineProperty實現雙向繫結,Object.defineProperty是es5上的方法,這也就是為什麼vue.js不相容ie8及其以下瀏覽器的原因。



作者:_小坦克_
連結:https://www.jianshu.com/p/570a84ca7a30
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。