es5的小方法Object.defineProperty

es5 的Object.defineProperty() 用來給一個對象定義一個屬性。vue的雙向綁定原理就是基於defineProperty的訪問器屬性實現的。vue

使用語法

Object.defineProperty(obj, key, descriptor) 須要定義傳入三個參數,這樣就能夠給對象obj定義一個key。chrome

  • obj: object類型,須要定義屬性的對象
  • key: string類型,屬性的名稱
  • descriptor: object類型, 一個描述符,也是重點關注的參數

descriptor 參數

第三個參數是一個對象有六個鍵值。分別是: 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, 就是屬性的值
});

運行結果 image 能夠看到是定義了一個屬性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;

image

更多的實例,能夠本身嘗試。blog

總結

說實話,defineProperty方法平時幾乎不用。畢竟如今工做上不少東西已經實現好了。咱們能夠用setter的這種方式觸發notity。相似於觀察者模式的方式監聽屬性,實現雙向數據綁定的做用。小中見大,細節的東西也是很重要的。這個方法的兼容性是IE9. IE8下面有些問題。

相關文章
相關標籤/搜索