# vue2 data 和 props

Vue中的data和props是怎么做到可以直接在实例下直接访问(this.attr);

先看initState

function initState(vm) {
  var opts = vm.$options;
  if (opts.props)
      initProps$1(vm, opts.props);
  if (opts.data) {
      initData(vm);
  } else {
      var ob = observe((vm._data = {}));
      ob && ob.vmCount++;
  }
}
1
2
3
4
5
6
7
8
9
10
11

可以看出 props 走了initProps$1(vm, opts.props);方法;

data 存在的话就是 initData(vm);,不存在的话就是 observe;

# data

# initData

function initData () {
  var data = vm.$options.data;
  data = vm._data = isFunction(data) ? getData(data, vm) : 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);
  }
  // proxy data on instance
  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];
    {
      if (methods && hasOwn(methods, key)) {
          warn$2("Method \"".concat(key, "\" has already been defined as a data property."), vm);
      }
    }
    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)) {
      proxy(vm, "_data", key);
    }
  }
  // observe data
  var ob = observe(data);
  ob && ob.vmCount++;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  • 1、取出我们传入的data,如果是方法就调用 getData 执行 data.call(vm, vm);并返回结果,并赋值为data。
  • 2、将data赋值给 vm._data;
  • 3、获取data所有key,并遍历,检测data是否和 methodsprops冲突,并执行proxy(vm, "_data", key);

# proxy

function proxy(target, sourceKey, key) {
  sharedPropertyDefinition.get = function proxyGetter() {
      return this[sourceKey][key];
  };
  sharedPropertyDefinition.set = function proxySetter(val) {
      this[sourceKey][key] = val;
  };
  Object.defineProperty(target, key, sharedPropertyDefinition);
}
1
2
3
4
5
6
7
8
9

通过Object.definePropertykey挂到target 及实例(vm)上;key的set为设置val到vm._data,get从vm._data取值。

# props

function initProps$1(vm, propsOptions) {
  var propsData = vm.$options.propsData || {};
  var props = (vm._props = shallowReactive({}));
  // cache prop keys so that future props updates can iterate using Array
  // instead of dynamic object key enumeration.
  var keys = (vm.$options._propKeys = []);
  var isRoot = !vm.$parent;
  // root instance props should be converted
  if (!isRoot) {
      toggleObserving(false);
  }
  var _loop_1 = function (key) {
      keys.push(key);
      var value = validateProp(key, propsOptions, propsData, vm);
      /* istanbul ignore else */
      {
          var hyphenatedKey = hyphenate(key);
          if (isReservedAttribute(hyphenatedKey) ||
              config.isReservedAttr(hyphenatedKey)) {
              warn$2("\"".concat(hyphenatedKey, "\" is a reserved attribute and cannot be used as component prop."), vm);
          }
          defineReactive(props, key, value, function () {
              if (!isRoot && !isUpdatingChildComponent) {
                  warn$2("Avoid mutating a prop directly since the value will be " +
                      "overwritten whenever the parent component re-renders. " +
                      "Instead, use a data or computed property based on the prop's " +
                      "value. Prop being mutated: \"".concat(key, "\""), vm);
              }
          });
      }
      // static props are already proxied on the component's prototype
      // during Vue.extend(). We only need to proxy props defined at
      // instantiation here.
      if (!(key in vm)) {
          proxy(vm, "_props", key);
      }
  };
  for (var key in propsOptions) {
      _loop_1(key);
  }
  toggleObserving(true);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

props的处理方式于data类似,最终也是调用 proxy。