# 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
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
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是否和
methods
和props
冲突,并执行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
2
3
4
5
6
7
8
9
通过Object.defineProperty
将key
挂到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
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。