vue雙向綁定原理之Object.defineProperty的應用

衆所周知,vue2.0的雙向數據綁定使用es6的Object.defineProperty方法實現的,本文我講會爲大家仔細講解之間的實現原理。

  • Object.defineProperty() 法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回此對象。
    這個方法接收三個參數,
   Object.defineProperty(obj, prop, desc)
  1. obj 需要定義屬性的當前對象.
  2. prop 當前需要定義的屬性名.
  3. desc 屬性描述符(configurable, enumerable, writable, set, get)

其實我們平時給對象添加屬性例如

let obj = {};
obj.name = 'lisi';

用Object.defineProperty()的話就是

var o = {};
Object.defineProperty(o, 'name', {
    enumerable: true,// 可被枚舉, 就是for in 循環能得到key
    configurable: true, // 能夠被改變,能夠被刪除。
    writable: true, // 可被賦值改變
    value: "list"
})

在我們的vue中其實就是利用Object.defineProperty中的get和set方法,獲取對象的值的時候會觸發get方法,設置值的時候會觸發set方法,從而去通知訂閱的對象達到響應式。注意: 設置了get,set 就不能設置writable屬性了否則會報錯。

 var o = {};
 var value = '';
Object.defineProperty(o, 'name', {
    enumerable: true,
    configurable: true,
     // writable: true,
    get() {
    	return value 
    },
   set(newValue) {
       value = newValue;
     }
   })

瞭解了上面Object.defineProperty()的基本用法,我們來模仿vue中對數據的劫持。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
     var obj = {
        name: 'yumang',
        age: 18,
        girls: ['美女']
     };
     function defineReactive(o, key, value){
        if (typeof value === 'object' && value != null && !Array.isArray(value)) {
          // 是非數組的引用類型
          reactify(value); // 遞歸
        }
        Object.defineProperty(o, key ,{
          configurable:true,
          enumerable:true,
          get(){
            // get 的時候做額外操作
            console.log('這裏在獲取'+ key + '的值')
            return value
          },
          set(newValue){
            // set 的時候做額外操作
            console.log('這裏在設置' + key + '的值'+ newValue)
            value = newValue;
          },
        })
     }
    /**
     *   o 要被劫持的對象
     * **/
    function reactify (o){
      let keys = Object.keys(o);
      for (let i=0; i< keys.length; i++ ){
        let key = keys[i];
        let value = o[key];
        /**
         * 1. 數組監聽
         * 2. 對象和普通值的監聽
         * **/
        if (Array.isArray(value)){
          // 如果是數組 就要對數組裏面的每一個屬性進行監聽
          for(let j = 0; j< value.length; j ++) {
            if (typeof value[j] === 'object')  reactify(value[j]) // 遞歸
          }
        }else {
          // 對象和普通值的監聽, 進入defineReactive的時候 如果對象裏面還有對象就需要使用遞歸
          defineReactive(o, key, value)
        }
      }
    }
    reactify(obj)
  </script>
</body>
</html>

以上兩個函數的遞歸調用我們就完成了對象屬性的監聽, 然而對於數組, 它的一些方法push等,卻沒有監聽到,vue裏面是怎麼處理的呢。 我們下次再一起學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章