天天看點

vue實作雙向資料綁定之Object.defineProperty()篇

前言

vue.js中使用ES5的Object.defineProperty()實作資料的雙向綁定

Object.defineProperty()原理

Object.defineProperty()可以用來修改對象的屬性,也可以在對象上新建立一個屬性

文法

Object.defineProperty(obj, prop, descriptor)

參數: obj -> 被定義或修改屬性的對象 

    prop -> 要定義或修改的屬性名稱

       descriptor -> 對屬性的描述

傳回值

函數将傳回傳遞給他的obj對象本身

描述符(descriptor)說明

該方法允許開發者精确的對對象屬性的定義和修改。通過正常指派進行屬性添加而建構的屬性會被枚舉器方法(如for..in循環或Object.keys方法)擷取,進而導緻屬性值被外部方法改變或删除。而Object.defineProperty()可以避免以上描述的情況,預設的,通過Object.defineProperty()添加的屬性是預設不可改變的。 

屬性描述參數(descriptor)主要由兩部分構成:資料描述符(data descriptor)和通路器描述符(accessor descriptor)。資料描述符就是一個包含屬性的值,并說明這個值可讀或不可讀的對象;通路器描述符就是包含該屬性的一對getter-setter方法的對象。一個完整的屬性描述(descriptor)必須是這兩者之一,并且不可以兩者都有。

資料描述符

  • value:屬性的值,預設為undefined
  • writable:可重寫性,如果為false,屬性的值就不能被重寫, 隻能為隻讀了,預設為false
  • configurable:可配置性,總開關,一旦為false,就不能再設定他的(value,writable,configurable),預設為false
  • enumerable:可枚舉性,是否可枚舉(是否能在for...in循環中周遊出來或在Object.keys中列舉出來),預設為false

通路器描述符

  • get:擷取資料時觸發
  • set:設定資料時觸發
var person= {};
Object.defineProperty(person, "name", {
  value: '張三'
})
console.log(person.name); // 張三      

我們隻設定了 value,别的并沒有設定

但是第一次的時候 可以簡單的了解為(暫時這樣了解)它會預設幫我們把writable,configurable,enumerable都設上值,而且值還都是false。

也就是說,上面代碼和下面是等價的的(僅限于第一次設定的時候)。

var person = {};
Object.defineProperty(person ,"name",{
  value: '張三',
  writable :false,
  enumerable: false,
  configurable: false
});
console.log(person.name); // 張三      

configurable

總開關,第一次設定 false 之後,第二次什麼設定也不行了,比如說

var person = {};
Object.defineProperty(person,"name",{
  configurable: false
});
Object.defineProperty(person,"name",{
  configurable: true
});
//error: Uncaught TypeError: Cannot redefine property: name      

就會報錯了。。

注意上面講的預設值。。。如果第一次不設定它會怎樣。。會幫你設定為false。。是以。。第二次。再設定會報錯

writable

如果設定為fasle,就變成隻讀了,不能進行修改。。

var person = {}; 
Object.defineProperty(person, "name", { 
      value : '張三',
      writable : false 
  }
);
console.log(person.name); // 列印 張三
person.name = '李四'; // 沒有錯誤抛出(在嚴格模式下會抛出,即使之前已經有相同的值)
console.log(person.name); // 列印 張三, 指派不起作用。      

enumerable

屬性特性 enumerable 定義了對象的屬性是否可以在 for...in 循環和 Object.keys() 中被枚舉。

var person = {}; 
Object.defineProperty(person, "name", { 
      value : '張三',
      enumerable: true
  }
);
console.log(Object.keys(person)); // 列印 ["name"]      
如果将enumerable改為false, for...in 類似      
var person = {}; 
Object.defineProperty(person, "name", { 
      value : '張三',
      enumerable: false
  }
);
console.log(Object.keys(person)); // 列印 []      

set 和 get

在 descriptor 中不能同時設定通路器(get 和 set)和 wriable 或 value,否則會錯,就是說想用 get 和 set,就不能用 writable 或 value 中的任何一個。

var person= {};
var temp = [];
Object.defineProperty(person, 'name', {
  set: function(newVal) {
    temp['name'] = newVal;
    console.log('為person設定新的姓名:' + newVal);
  },
  get: function() {
    var _name =  temp['name'] || '預設姓名';
    console.log('擷取person的姓名:' +  _name);
    return _name;
  }
});
person.name = '張三';      // 列印 擷取person的姓名:張三
console.log(person.name)  // 列印 擷取person的姓名:張三(如果不設定name,這裡會列印'預設姓名')      

轉載于:https://www.cnblogs.com/kunmomo/p/9953215.html

繼續閱讀