Object的变化侦测
变化侦测就是侦测数据的变化。当数据发生变化时,要能侦测到并且发出通知。
Object可以通过 Object.defineProperty 将属性转换成getter/setter 的形式来追踪变化。读取数据时会触发 getter ,修改数据时会触发 setter。
我们需要在 getter 中收集有哪些依赖使用了数据,当 setter 被触发时,去通知 getter 中收集的依赖数据发生了变化。
收集依赖需要为依赖找寻一个可以存储依赖的地方,为此我们创建了 Dep ,它用来收集依赖,删除依赖和向依赖发送消息等。
所谓的依赖,其实就是 Watcher 。只有 Watcher 触发的 getter 才会收集依赖。哪个 Watcher 触发了getter,就把哪个 Watcher 收集到 Dep 中。当数据发生变化时,会循环依赖列表,把所有的 Watcher 都通知一遍。
Watcher 的原理是先把自己设置到全局唯一的指定位置(例如 window.target),然后读取数据。因为读取了数据,所以会触发这个数据的 getter。接着,在 getter 中就会从全局唯一的那个位置读取当前正在读取数据的 Watcher ,并把这个 Watcher 收集到 Dep 中去,通过这样的方式,Watcher 可以主动去订阅任意一个数据的变化。
此外,我们创建了 Observer 类,它的作用是把一个 object 中的所有数据(包括子数据)都转换成响应式的,也就是它会侦测 object 中的所有数据(包括子数据)的变化。
由于 ES6 之前 JavaScript 并没有提供元编程的能力,所以在对象上新增属性和删除属性都无法被追踪到。为了解决这个问题,Vue.js提供了两个 API ---- vm. s e t 与 v m . set 与 vm. set与vm.delete。
下图给出了Data、Observer、Dep 和 Watcher 之间的关系。
Data 通过 Observer 转换成了 getter/setter 的形式来追踪变化。
当外界通过 Watcher 读取数据时,会触发 getter 从而将 Watcher 添加到依赖中。
当数据发生了变化时,会触发 setter ,从而向 Dep 中的依赖 (Watcher)发送通知。
Watcher接受到通知后,会向外界发送通知,变化通知到外界后可能会触发视图更新,也有可能触发用户的某个回调函数等。