响应式对象添加

        响应式数据中对于对象新增/删除属性以及数组的下标访问修改和添加数据等的变化观测不到。通过Vue.set以及修改数组原型方法的API可以去解决这些问题,本质上都是对添加的对象执行defineReactive写出依赖收集机制和派发更新机制,然后手动通过ob.dep.notify()触发派发更新。

检测变化的注意事项

        通过前面几节的分析,我们对响应式数据对象以及它的 getter 和 setter 部分做了了解,但是对于一些特殊情况是需要注意的,接下来我们就从源码的角度来看 Vue 是如何处理这些特殊情况的。

对象添加属性

        对于使用 Object.defineProperty 实现响应式的对象,当我们去给这个对象添加一个新的属性的时候,是不能够触发它的 setter 的,比如:

响应式对象添加_第1张图片
添加新属性为非响应式

        但是添加新属性的场景我们在平时开发中会经常遇到,那么 Vue 为了解决这个问题,定义了一个全局 API Vue.set 方法,它在 src/core/global-api/index.js 中初始化:Vue.set = set

这个 set 方法的定义在 src/core/observer/index.js 中:

响应式对象添加_第2张图片
set动态添加响应式属性

        set 方法接收 3个参数,target 可能是数组或者是普通对象,key 代表的是数组的下标或者是对象的键值,val 代表添加的值。首先判断如果 target 是数组且 key 是一个合法的下标,则之前通过 splice 去添加进数组然后返回,这里的 splice 其实已经不仅仅是原生数组的 splice 了,稍后我会详细介绍数组的逻辑。接着又判断 key 已经存在于 target 中,则直接赋值返回,因为这样的变化是可以观测到了。接着再获取到 target.__ob__ 并赋值给 ob,之前分析过它是在 Observer 的构造函数执行的时候初始化的,表示 Observer 的一个实例,如果它不存在,则说明 target 不是一个响应式的对象,则直接赋值并返回。最后通过 defineReactive(ob.value, key, val) 把新添加的属性变成响应式对象,然后再通过 ob.dep.notify() 手动的触发依赖通知,还记得我们在给对象添加 getter 的时候有这么一段逻辑:

响应式对象添加_第3张图片
在给对象添加 getter 时的逻辑

        在 getter 过程中判断了 childOb,并调用了 childOb.dep.depend() 收集了依赖,这就是为什么执行 Vue.set 的时候通过 ob.dep.notify() 能够通知到 watcher,从而让添加新的属性到对象也可以检测到变化。这里如果 value 是个数组,那么就通过 dependArray 把数组每个元素也去做依赖收集。

你可能感兴趣的:(响应式对象添加)