「这是我参与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: anyasRootData: ?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)
那么关于响应式的入口我们就找到了