訂閱者 Dep
首先實(shí)現(xiàn)一個(gè)訂閱者Dep,它的主要作用是用來存放watcher觀察者對(duì)象
class Dep {
constructor () {
/*用來存放watcher對(duì)象的數(shù)組*/
this.subs = [];
}
/*在subs中添加一個(gè)Watcher對(duì)象*/
addSub (sub) {
this.subs.push(sub);
}
/*通知所有watcher對(duì)象更新視圖*/
notify () {
this.subs.forEach((sub) => {
sub.update();
});
}
}
觀察者 Watcher
class Watcher {
constructor () {
/* 在new一個(gè)Watcher對(duì)象時(shí)將該對(duì)象賦值給Dep.target戴而,在get中會(huì)用到 */
Dep.target = this;
}
/* 更新視圖的方法 */
update () {
console.log('視圖更新了');
}
}
Dep.target = null;
依賴收集
接下來修改一下defineReactive以及Vue的構(gòu)造函數(shù),來完成依賴收集碟贾。
function defineReactive(obj, key, val) {
const dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
/* 將Dep.target(即當(dāng)前的Watcher對(duì)象存入dep的subs中) */
dep.addSub(Dep.target);
return val;
},
set: function reactiveSetter (newVal) {
if (newVal === val) {
return;
}
/* 在set的時(shí)候觸發(fā)dep的notify來通知所有的Watcher對(duì)象更新視圖 */
dep.notify();
}
});
}
class Vue {
constructor (options) {
this._data = options.data;
observer(this._data);
/* 新建一個(gè)Watcher觀察者對(duì)象,這時(shí)候Dep.target會(huì)指向這個(gè)Watcher對(duì)象 */
new Watcher();
/* 在這里模擬render的過程轨域,為了觸發(fā)test屬性的get函數(shù) */
console.log('render', this._data.test);
}
}
小結(jié)
首先在observer的過程中會(huì)注冊(cè)get方法袱耽,該方法用來進(jìn)行依賴收集。在它的閉包中會(huì)有一個(gè)Dep對(duì)象干发,這個(gè)對(duì)象用來存放Watcher對(duì)象的實(shí)例朱巨。其實(shí)依賴收集的過程就是把watcher實(shí)例存放到對(duì)應(yīng)的Dep對(duì)象中去。get方法可以讓當(dāng)前的watcher對(duì)象(Dep.target)存放到它的subs中(通過addSub方法)铐然。在數(shù)據(jù)發(fā)生變化時(shí)蔬崩,set會(huì)調(diào)用Dep對(duì)象的notify方法通知它內(nèi)部的watcher對(duì)象進(jìn)行視圖更新。