美文网首页
解析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