es5 的Object.defineProperty() 用來給一個對象定義一個屬性。vue的雙向綁定原理就是基於defineProperty的訪問器屬性實現的。vue
Object.defineProperty(obj, key, descriptor)
須要定義傳入三個參數,這樣就能夠給對象obj定義一個key。chrome
第三個參數是一個對象有六個鍵值。分別是: configurable(boolean, 默認true), enumerable(boolean, 默認true), writable(boolean, 默認true), value(any, 默認undefined), get(function, 默認undefined), set(function, 默認undefined) 。其中writable, value任意一個和get, set任一一個都不能夠同時存在。爲何呢? 關於紅寶書上的介紹,一上來就是一段教科書的描述,比較晦澀。將defineProperty方法定義的屬性分爲兩種類型:數據屬性和訪問器屬性。 因此descriptor參數的不一樣決定了相應的屬性的類型。 故descriptor有兩種方式函數
描述數據屬性(平時用obj.name = '123', 其實就是默認用這種方式定義的):this
{ configurable: false, // 默認爲true, 描述可否被改變,好比delete或者修改爲訪問器屬性 enumerable: false, // 默認爲true, 描述可否被 in 枚舉,好比for-in writable: false, // 默認true, 描述是否能被更改 value: [1, 2, 3], // 默認undefined, 就是屬性的值 }
描述訪問器屬性es5
{ configurable: false, // 默認爲true, 描述可否被改變,好比delete或者修改爲訪問器屬性 enumerable: false, // 默認爲true, 描述可否被 in 枚舉,好比for-in get: function() { return this.name }, // 默認undefined, getter函數 set: function(newVal) { this.name = newVal }, // 默認undefined, setter函數 }
直接在chrome下進行:3d
var obj = {}; Object.defineProperty(obj, 'name', { configurable: false, // 默認爲true, 描述可否被改變,好比delete或者修改爲訪問器屬性 enumerable: false, // 默認爲true, 描述可否被for-in枚舉 writable: false, // 默認true, 描述是否能被更改 value: 'wython' // 默認undefined, 就是屬性的值 });
運行結果 能夠看到是定義了一個屬性name.這種方式和obj.name = 'wython'; 其實沒啥區別。在這裏面我把configrable, enumerable, writable改爲false。 因此若是參數去改值,或者遍歷, 都是不行的。雙向綁定
for(const i in obj) { console.log(i) } // 結果: undefined delete obj.name; // 無效 obj.name = 'Another wython'; // 無效
Object.defineProperty(obj, '_name', { configurable: true, enumerable: true, get: function() { return this.name }, set: function(newVal) { // 咱們能夠嘗試更改name的值,由於是不可更改因此是無效的 this.name = newVal; } }) // 驗證 obj._name = 1; // 無效,緣由是訪問器屬性監聽的是不可更改的name屬性
因此說訪問器屬性監聽的是另外一個屬性,若是監聽的是自身,會報堆棧溢出的錯誤。code
好比:對象
Object.defineProperty(obj, '_self', { configurable: true, enumerable: true, get: function() { return this._self }, set: function(newVal) { // 咱們能夠嘗試更改name的值,由於是不可更改因此是無效的 this._self = newVal; } }) obj._self;
更多的實例,能夠本身嘗試。blog
說實話,defineProperty方法平時幾乎不用。畢竟如今工做上不少東西已經實現好了。咱們能夠用setter的這種方式觸發notity。相似於觀察者模式的方式監聽屬性,實現雙向數據綁定的做用。小中見大,細節的東西也是很重要的。這個方法的兼容性是IE9. IE8下面有些問題。