数据响应式原理

看源码的时候思考以下问题

  • vm.msg ={ count: 0 } 重新给属性赋值,是否是响应式
  • vm.arr[0] = 4 给数组元素赋值,视图是否会更新
  • vm.arr.length = 0 修改数组的length,视图是否会更新
  • vm.arr.push(4) 视图是否会更新

响应式整体流程

响应式流程图open in new window

我们已经知道了整体的流程,在_init方法中,我们可以看到调用了initState方法。在initState方法中,我们可以看到

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  // 这里就是响应式的入口了
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

我们只要看当opts.data存在的时候就可以了。调用了initData,省略一些判断代码我们可以看到,这里就是循环datakey, 通过proxy将所有的key代理到了vm中。最后调用了observe(data)进入data的响应式流程

function initData (vm: Component) {
  let data = vm.$options.data
  data = vm._data = typeof data === 'function'
    ? getData(data, vm)
    : data || {}
  const keys = Object.keys(data)
  let i = keys.length
  while (i--) {
    const key = keys[i]
     if (!isReserved(key)) {
      proxy(vm, `_data`, key)
    }
  }
  // observe data
  observe(data, true /* asRootData */)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export function observe (value: any, asRootData: ?boolean): Observer | void {
  if (!isObject(value) || value instanceof VNode) {
    return
  }
  let ob: Observer | void
  // 是否存在ob,如果存在则直接赋值返回
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else if (
    shouldObserve &&
    !isServerRendering() &&
    (Array.isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value._isVue
  ) {
    // 创建一个Observer对象
    ob = new Observer(value)
  }
  // ob.vmCount++
  if (asRootData && ob) {
    ob.vmCount++
  }
  // 返回对象
  return ob
}
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
Last Updated: