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里面是怎么处理的呢。 我们下次再一起学习。

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