7.3 initData

data在初始化选项合并时会生成一个函数,只有在执行函数时才会返回真正的数据,所以initData方法会先执行拿到组件的data数组,并且会对对象每个属性的命名进行校验,保证不能和props,methods重复。最后的核心方法是observe,observe方法是将数据对象标记为响应式对象,并对对象的每个属性进行响应式处理。与此同时,和props的代理处理方式一样,proxy会对data做一层代理,直接通过vm.XXX可以代理访问到vm._data上挂载的对象属性。

  1. function initData(vm) {
  2. var data = vm.$options.data;
  3. // 根实例时,data是一个对象,子组件的data是一个函数,其中getData会调用函数返回data对象
  4. data = vm._data = typeof data === 'function'? getData(data, vm): data || {};
  5. var keys = Object.keys(data);
  6. var props = vm.$options.props;
  7. var methods = vm.$options.methods;
  8. var i = keys.length;
  9. while (i--) {
  10. var key = keys[i];
  11. {
  12. // 命名不能和方法重复
  13. if (methods && hasOwn(methods, key)) {
  14. warn(("Method \"" + key + "\" has already been defined as a data property."),vm);
  15. }
  16. }
  17. // 命名不能和props重复
  18. if (props && hasOwn(props, key)) {
  19. warn("The data property \"" + key + "\" is already declared as a prop. " + "Use prop default value instead.",vm);
  20. } else if (!isReserved(key)) {
  21. // 数据代理,用户可直接通过vm实例返回data数据
  22. proxy(vm, "_data", key);
  23. }
  24. }
  25. // observe data
  26. observe(data, true /* asRootData */);
  27. }

最后讲讲observe,observe具体的行为是将数据对象添加一个不可枚举的属性ob,标志对象是一个响应式对象,并且拿到每个对象的属性值,重写getter,setter方法,使得每个属性值都是响应式数据。详细的代码我们后面分析。