# 组件内部状态小结
通过前一篇文章,我们现在知道,当我初始化一个vue实例的时候,其内部会将我们传入的props, methods, data, computed, watch选项做一些预处理后,然后再挂载到我们的当前实例this上
下面以一个简单的小例子说明问题。
# 例子:
new Vue({
props: {
type: String,
default: 'uncle-yang'
},
data: function(){
return {
age: 30
}
},
computed: {
showInfo: function(){
return `my name is ${this.name}, i'm ${this.age}`;
}
},
watch: {
age: function(newVal, oldVal){
console.log(`my new age is ${newVal}`);
}
},
methods: {
getName(){
return `Hello! i'm ${this.name}`
}
}
})
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
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
# props
- 获取到
props选项 - 定义内部变量
_props - 调用
validateProp()验证,获取name的值 - 通过
defineReactive把name的值挂在_props上,且完成数据劫持- 生成和
name相关的Dep实例 - 当访问
name值的时候触发getter函数,有Dep.target的情况下会收集依赖 - 当设置
name值的时候触发setter函数,调用dep.notify通知依赖name的Watcher实例
- 生成和
- 把值通过
proxy挂载this(到当前实例)上,以便于当访问this.name的时候直接响应到上述逻辑
# methods
- 获取到
props选项 - 通过
bind方法改变getName函数的this指向 - 把改变了
this指向的getName函数挂载到当前vue实例上
# data
- 获取到
data选项(一个函数) - 调用
getData函数获取data函数中返回的对象{age: 30} - 定义内部变量
_data,且指向上述返回的对象{age: 30} - 调用
proxy函数,把_data中的属性(age)代理到this(当前实例)上 - 调用
observe函数得到一个Oberver实例Oberver中,通过调用defineReactive来观察_data的age属性
# computed
- 获取到
computed选项 - 定义内部变量
_computedWatchers - 创建
showInfo对应的Watcher实例,并且把该实例缓存到_computedWatchers- 其中
showInfo函数传入了Watcher对应的expOrFn变量 - 而
expOrFn被Watcher内部的get函数包装 get函数执行时,会先调用pushTarget函数开启收集依赖的关- 再执行把
this指向当前vue实例的函数function(){return ‘my name is ${this.name}, i'm ${this.age}’} - 当函数运行到
this.name和this.age时,触发其各自被defineReactive劫持的getter函数 - 此时
Dep.target有_computedWatchers[showInfo]对应的Watcher实例,从而执行getter中的dep.depend() - 然后执行
_computedWatchers[showInfo].addDep(dep) - 在
Watcher.addDep函数中,又把_computedWatchers[showInfo]对应的Watcher实例push到了dep.subs数组中 - 从此完成
showInfo对name和age依赖的收集 - 且得到了函数运行的值
my name is uncle-yang, i'm 30,并且赋值给Watcher.value - 当给
name和age设置新值时,触发其各自被defineReactive劫持的setter函数 - 然后执行到
dep.notify() - 从而调用
dep.subs中所有Watcher.update方法 - 由于
computed默认选项{lazy: true},所以只是改变了Watcher内部变量的值dirty = true
- 其中
- 调用
createComputedGetter把showInfo包装成一个对象,其getter返回Watcher.value
# watch
获取到
watch选项获取到
age选项调用
this.$watch('age', ageFun),这个方法在stateMixin方法中混入在
$watch中执行new Watcher(vm, 'age', ageFun, {user: true})- 在
watcher实例中 watcher.getter为一个函数function(){return vm.age}- 在调用
get方法是完成watcher依赖的收集 - 当
age改变时,触发传入的ageFun回调函数
# 小结
- 状态初始化的顺序是
props,method,data,computed,watch,所以访问顺序也是有区别的,例如可以在data中访问props,但是不能反过来
- 在
← 组件内部状态 模板编译都经历了那些什么 →