美文网首页
解析vue如何实现数据代理

解析vue如何实现数据代理

作者: 变量只提升声明不提升赋值 | 来源:发表于2020-08-20 11:11 被阅读0次
      const vm = new MVVM({
        el: "#test",
        data: {
          name: '张三2'
        }
      })
    先new一个vue配置对象
    
    数据代理其实就是利用了Object.defineProperty方法来给
    new出来的一个vue对象添加一个和vue中data里相同属性名的属性,
    所以vue中访问data里的属性,不需要this.data.name   
    只需要this.name 就可以访问到,这是因为,我们在创建这个vue实例的时候,
    就已经把data中的数据代理给了vm  也就是vue这个对象本身  所以相当于vue里面也有了name这个属性
    
    我们在new MVVM的时候,就会去调用一个构造函数
    
    /*
    相关于Vue的构造函数
     */
    function MVVM(options) {
      // 将选项对象保存到vm
      this.$options = options;
      // 将data对象保存到vm和data变量中
      var data = this._data = this.$options.data;
      //将vm保存在me变量中
      var me = this;
      // 遍历data中所有属性
      Object.keys(data).forEach(function (key) { // 属性名: name
        // 对指定属性实现代理
        me._proxy(key);
      });
    
    MVVM.prototype = {
      $watch: function (key, cb, options) {
        new Watcher(this, key, cb);
      },
    
      // 对指定属性实现代理
      _proxy: function (key) {
        // 保存vm
        var me = this;
        // 给vm添加指定属性名的属性(使用属性描述)
        Object.defineProperty(me, key, {
          configurable: false, // 不能再重新定义
          enumerable: true, // 可以枚举
          // 当通过vm.name读取属性值时自动调用
          get: function proxyGetter() {
            // 读取data中对应属性值返回(实现代理读操作)
            return me._data[key];
          },
          // 当通过vm.name = 'xxx'时自动调用
          set: function proxySetter(newVal) {
            // 将最新的值保存到data中对应的属性上(实现代理写操作)
            me._data[key] = newVal;
          }
        });
      }
    };
    
    可以看到上述代码中, new MVVM()就是调用这个构造函数,里面会传一个配置对象作为参数,也就是
     {
        el: "#test",
        data: {
          name: '张三2'
        }
      }
    MVVM构造函数在接收到这个配置对象之后,首先把这个对象保存起来,赋值给$options 
       
      this.$options = options;
    
    此函数中的this均指向vm    即   const vm = new MVVM  里的vm
    然后再把原对象中的data对象,赋值给vm里的_data,同时又保存在data中
    
     var data = this._data = this.$options.data;
    
    
    接着调用对象的keys方法得到此对象中可枚举的所有属性组成的数组,遍历一次,
    将每个属性都代理给vm  即me._proxy(key);
    
     Object.keys(data).forEach(function (key) { // 属性名: name
        // 对指定属性实现代理
        me._proxy(key);
      });
    
    接下来,进入_proxy方法,去实现代理
    
      // 对指定属性实现代理
      _proxy: function (key) {
        // 保存vm
        var me = this;
        // 给vm添加指定属性名的属性(使用属性描述)
        Object.defineProperty(me, key, {
          configurable: false, // 不能再重新定义
          enumerable: true, // 可以枚举
          // 当通过vm.name读取属性值时自动调用
          get: function proxyGetter() {
            // 读取data中对应属性值返回(实现代理读操作)
            return me._data[key];
          },
          // 当通过vm.name = 'xxx'时自动调用
          set: function proxySetter(newVal) {
            // 将最新的值保存到data中对应的属性上(实现代理写操作)
            me._data[key] = newVal;
          }
        });
      }
    };
    
    _proxy方法接收一个参数key  即原data对象中每个可枚举的属性的属性名
    
    调用Object.defineProperty方法
    先配置属性
    configurable: false, // 不能再重新定义
    enumerable: true, // 可以枚举
    
    get方法 和set方法就实现了数据代理
    
          // 当通过vm.name读取属性值时自动调用
          get: function proxyGetter() {
            // 读取data中对应属性值返回(实现代理读操作)
            return me._data[key];
          },
          // 当通过vm.name = 'xxx'时自动调用
          set: function proxySetter(newVal) {
            // 将最新的值保存到data中对应的属性上(实现代理写操作)
            me._data[key] = newVal;
          }
    
    当我们 写语句 vm.xxx的时候,就会去调用到get方法, get方法会返回me._data.xxx
    同样的当我们给vm.xxx赋值的时候,就回去调用set方法,
    
    
    在这个构造函数中,data中的数据都会通过defineProperty方法被添加到vm对象中,
    vm对象里新增的这些属性都是可操控的,被监视的,
    也就是表面上看起来我们是在操作vm.xxx其实实际上我们操作的是vm._data里的xxx 也就是data中的xxx
    
    所以数据代理的根本就是我们想要操作  a.b.xxx  
    经过数据代理后我们可以实现表面操作a.xxx其实操作的是a.b.xxx
    

    相关文章

      网友评论

          本文标题:解析vue如何实现数据代理

          本文链接:https://www.haomeiwen.com/subject/hqlsjktx.html