# 组件内部状态小结

通过前一篇文章,我们现在知道,当我初始化一个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

# props

  • 获取到props选项
  • 定义内部变量_props
  • 调用validateProp()验证,获取name的值
  • 通过defineReactivename的值挂在_props上,且完成数据劫持
    • 生成和name相关的Dep实例
    • 当访问name值的时候触发getter函数,有Dep.target的情况下会收集依赖
    • 当设置name值的时候触发setter函数,调用dep.notify通知依赖nameWatcher实例
  • 把值通过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来观察_dataage属性

# computed

  • 获取到computed选项
  • 定义内部变量_computedWatchers
  • 创建showInfo对应的Watcher实例,并且把该实例缓存到_computedWatchers
    • 其中showInfo函数传入了Watcher对应的expOrFn变量
    • expOrFnWatcher内部的get函数包装
    • get函数执行时,会先调用pushTarget函数开启收集依赖的关
    • 再执行把this指向当前vue实例的函数function(){return ‘my name is ${this.name}, i'm ${this.age}’}
    • 当函数运行到this.namethis.age时,触发其各自被defineReactive劫持的getter函数
    • 此时Dep.target_computedWatchers[showInfo]对应的Watcher实例,从而执行getter中的dep.depend()
    • 然后执行_computedWatchers[showInfo].addDep(dep)
    • Watcher.addDep函数中,又把_computedWatchers[showInfo]对应的Watcher实例push到了dep.subs数组中
    • 从此完成showInfonameage依赖的收集
    • 且得到了函数运行的值my name is uncle-yang, i'm 30,并且赋值给Watcher.value
    • 当给nameage设置新值时,触发其各自被defineReactive劫持的setter函数
    • 然后执行到dep.notify()
    • 从而调用dep.subs中所有Watcher.update方法
    • 由于computed默认选项{lazy: true},所以只是改变了Watcher内部变量的值dirty = true
  • 调用createComputedGettershowInfo包装成一个对象,其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,但是不能反过来
上次更新: 6/27/2019, 11:43:03 AM