前言
Vue.js 一个核心思想是数据驱动。所谓数据驱动,是指视图是由数据驱动生成的,我们对视图的修改,不会直接操作 DOM,而是通过修改数据。
DOM 变成了数据的映射,我们所有的逻辑都是对数据的修改,而不用碰触 DOM,这样的代码非常利于维护。
概述
Vue.js 是通过数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。
第一步 - 实现一个订阅器(Dep)
target
指向当前正在评估的目标观察者,一个Dep
通常有一个可观察的对象(subs
),可以有多个指向它的指令
// observe.js
class Dep {
target = null
constructor() {
this.subs = []
}
// 收集观察者
addSub(watcher) {
this.subs.push(watcher)
}
// 通知观察者去更新视图
notify() {
this.subs.forEach(watcher => {
watcher.upDate()
})
}
}
第二步 - 实现一个Observe
Observe 劫持目标对象的 getter / setter 收集依赖关系并调度更新,参考文档: Object.defineProperty() - JavaScript | MDN
export class Observe {
constructor (data) {
this.observe(data)
}
observe (data) {
if (data && typeof data == 'object') {
Object.keys(data).forEach((key) => {
this.defineReactive(data, key, data[key])
})
}
}
defineReactive (data, key, value) {
// 递归遍历
this.observe(value)
// 为每一个key创建依赖收集器
const dep = new Dep()
Object.defineProperty(data, key, {
enumerable: true,
configurable: false,
get () {
// 当有订阅时才往Dep中添加观察者
Dep.target && dep