Vue数据代理之data源码分析

Vue中的数据代理

​ 通过vm对象来代理data对象中的属性实现读写

// 初始化状态
function initState(vm) {
    // 获取Vue实例中 属性 信息
      var opts = vm.$options;
    // 判断 props 是否被进行配置
      if (opts.props)
          initProps$1(vm, opts.props);
      initSetup(vm);
    // 判断 methods 是否被配置
      if (opts.methods)
          initMethods(vm, opts.methods);
    // 判断 data 是否被配置
      if (opts.data) {
          // 初始化 data
          initData(vm);
      }
      else {
          var ob = observe((vm._data = {}));
          ob && ob.vmCount++;
      }
      if (opts.computed)
          initComputed$1(vm, opts.computed);
      if (opts.watch && opts.watch !== nativeWatch) {
          initWatch(vm, opts.watch);
      }
  }	

// 初始化 data
  function initData(vm) {
      // 获取 vue实例中的 data
      var data = vm.$options.data;
      // 如果data是函数就直接获得 data中的数据 否则直接拿设置的对象
      // vm._data 与 vm.$options.data 指向 同一个引用,此时操作 vm._data中的数据就是操作Vue实例中的data
      data = vm._data = isFunction(data) ? getData(data, vm) : data || {};
      // 判断data是否是对象
      if (!isPlainObject(data)) {
          data = {};
          warn$2('data functions should return an object:\n' +
                  'https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function', vm);
      }
      // vue实例的数据代理
      // 获取vue实例(vm.$options.data)中 data对象 的 属性名数组
      var keys = Object.keys(data);
      var props = vm.$options.props;
      var methods = vm.$options.methods;
      // 获取属性名数组的长度
      var i = keys.length;
      // 循环遍历
      while (i--) {
          // 获取当前索引下的属性名
          var key = keys[i];
          {  
              // 检查当前的data对象中属性的属性名是否已经在 methods 中被使用
              if (methods && hasOwn(methods, key)) {
                  warn$2("Method \"".concat(key, "\" has already been defined as a data property."), vm);
              }
          }
          // 检查当前的data对象中属性的属性名是否已经在 props 中被使用
          if (props && hasOwn(props, key)) {
              warn$2("The data property \"".concat(key, "\" is already declared as a prop. ") +
                      "Use prop default value instead.", vm);
          }
          // 只要元素不是以 _ 或 $ 开头就执行数据代理
          else if (!isReserved(key)) {
            // 数据代理,将 vm.$options.data 中的 属性名 添加到 vm._data上
              proxy(vm, "_data", key);
          }
      }
      // 监测 data 数据变化
      var ob = observe(data);
      ob && ob.vmCount++;
  }
// 数据代理
/* targrt: 目标对象
*  sourceKey: 要添加的属性
*  key: 属性的值
*/
  function proxy(target, sourceKey, key) {
      // 设置数据代理的属性值的get方法
      sharedPropertyDefinition.get = function proxyGetter() {
          // 等效于 return this.sourceKey.key;
          return this[sourceKey][key];
      };
      // 设置数据代理的属性值的set方法
      sharedPropertyDefinition.set = function proxySetter(val) {
          // 等效于 this.sorceKey.key = val;
          this[sourceKey][key] = val;
      };
      // 数据代理  给vm添加属性 使之可以以 vm.name 的形式操作 vm._data中的数据,并且在标签中可以使用{{name}}的形式来访问 vm.$options.data.name,若不为vm设置数据代理则在标签中就要使用{{_data.name}}的形式来访问属性 vm.$options.data.name,相比较之下设置数据代理之后操作更方便快捷
      Object.defineProperty(target, key, sharedPropertyDefinition);
  }
// 数据代理的属性值
  var sharedPropertyDefinition = {
      // 可以被遍历
      enumerable: true,
      // 属性可以被删除
      configurable: true,
      get: noop,
      set: noop
  };
  /**
   * 检查字符串是否以 _ 或者 $ 开头
   */
  function isReserved(str) {
      var c = (str + '').charCodeAt(0);
      return c === 0x24 || c === 0x5f;
  }

​ 通过源码可知,如果vue实例中(之后用vm代替)的$options.data有值,则执行 vm._data = vm.$options.data,因为 vm._data 与 vm.$options.data为同一个引用,所以修改 vm.$options.data对象中的属性值的时候,vm._data对象中的属性也会发生改变,反之亦然;最后执行了 proxy(vm, _data, key)方法,而在proxy方法中做的事情就是为每个属性设置get、set方法最后再将此属性代理至vm也就是this,至此我们就可以使用 this.属性名 或者在标签中使用 {{属性名}}来访问Vue配置项中的data数据。

posted @   不凡34  阅读(73)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示