
那么订阅了同个微信公众号的人有成千上万个,那么首先想到的就是要 new Array() 去存放这些人(html 节点)吧。于是就有了如下代码:
// observer.js
function Dep() {
this.subs = [] // 存放订阅者
}
Dep.prototype = {
addSub: function(sub) { // 添加订阅者
this.subs.push(sub)
},
notify: function() { // 通知订阅者更新
this.subs.forEach(function(sub) {
sub.update()
})
}
}
function observe(data) {...}
function defineReactive(data, key, value) {
var dep = new Dep()
observe(value) // 遍历嵌套对象
Object.defineProperty(data, key, {
get: function() {
if (Dep.target) { // 往订阅器添加订阅者
dep.addSub(Dep.target)
}
return value
},
set: function(newValue) {
if (value !== newValue) {
console.log('值发生变化', 'newValue:' + newValue + ' ' + 'oldValue:' + value)
value = newValue
dep.notify()
}
}
})
}
初看代码也比较顺畅了,但可能会卡在 Dep.target 和 sub.update,由此自然而然地将目光移向 watcher,
// watcher.js
function Watcher(vm, exp, cb) {
this.vm = vm
this.exp = exp
this.cb = cb
this.value = this.get()
}
Watcher.prototype = {
update: function() {
this.run()
},
run: function() {
// ...
if (value !== oldVal) {
this.cb.call(this.vm, value) // 触发 compile 中的回调
}
},
get: function() {
Dep.target = this // 缓存自己
const value = this.vm.data[this.exp] // 强制执行监听器里的 get 函数
Dep.target = null // 释放自己
return value
}
}
从代码中可以看到当构造 Watcher 实例时,会调用 get() 方法,接着重点关注 const value = this.vm.data[this.exp] 这句,前面说了当要获取 Model(JS 对象) 的值时,会自动调用 Object.defineProperty 的 get 方法,也就是当执行完这句的时候,Dep.target 的值传进了 observer.js 中的 Object.defineProperty 的 get 方法中。同时也一目了然地在 Watcher.prototype 中发现了 update 方法,其作用即触发 compile 中绑定的回调来更新界面。至此解释了 Observer 中 Dep.target 和 sub.update 的由来。
来归纳下 Watcher 的作用,其充当了 observer 和 compile 的桥梁。
1 在自身实例化的过程中,往订阅器(dep) 中添加自己
2 当 model 发生变动,dep.notify() 通知时,其能调用自身的 update 函数,并触发 compile 绑定的回调函数实现视图更新
最后再来看下生成 Watcher 实例的 compile.js 文件。

