Vue.js 源码分析 - 数据响应式原理-处理入口

400 阅读2分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战

数据响应式原理-处理入口

通过查看源码解决下面问题

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

响应式处理的入口

整个响应式处理的过程是比较复杂的,下面我们先从:

  • src/core/instance/init.js
    • initState(vm) // 初始化 vm 的 _props/methods/_data/computed/watch
    • 处理刷了 _data、_prop、methods 等
  • src/core/instance/state.js 初始化
    if (opts.data) {
        initData(vm)
    } else {
        observe(vm._data = {}, true /* asRootData */)
    } 
    
    • initData(vm) 的作用是 将data中的数据注入到vue实例,并且转换成响应式对象
    • observe 就是我们响应式处理的入口

initData

initData中我们可以看见以下这段代码:

 while (i--) {
    const key = keys[i]
    if (process.env.NODE_ENV !== 'production') {
      if (methods && hasOwn(methods, key)) {
        warn(
          `Method "${key}" has already been defined as a data property.`,
          vm
        )
      }
    }
    if (props && hasOwn(props, key)) {
      process.env.NODE_ENV !== 'production' && warn(
        `The data property "${key}" is already declared as a prop. ` +
        `Use prop default value instead.`,
        vm
      )
    } else if (!isReserved(key)) {
      proxy(vm, `_data`, key)
    }
  }

这是为了判断 data 上的成员是否和 props/methods 重名

当这块循环结束之后,我们可以看见:

// observe data
  // 响应式处理
  observe(data, true /* asRootData */)

这就是我们进行转换的入口

observe

参数:

  • value: any
  • asRootData: ?boolean

这个方法上有一段官方给的注释对象

尝试为一个值创建一个observe对象,如果创建成功,则返回新的observe对象,或返回一个已经存在的observe对象。 也就是我们传入的参数 value 如果也就是 observe对象了,就直接返回

这里判断传入的参数 value 是否是对象或者是 VNode

if (!isObject(value) || value instanceof VNode) {
    return
}

接下来:

判断 value 是否有 __ob__(observer对象) 属性

if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ...
} else {
    ...
}

总结

这个函数就是响应式的入口,这个函数的核心就是

// 创建一个 Observer 对象
 ob = new Observer(value)

那么关于响应式的入口我们就找到了