完善一下watcher的listenFn函數(shù)
目前的scope代碼很簡(jiǎn)單,watch方法用來注冊(cè)一個(gè)watcher税稼,digest方法用來執(zhí)行所有的watcher,將執(zhí)行后的值和上一次的值進(jìn)行比對(duì),如果不一樣针姿,就執(zhí)行watcher的listen方法:
問題是窗声,如果我想在listen這個(gè)回調(diào)函數(shù)里面拿到新值和舊值進(jìn)行操作相恃,目前是不行的,看看下面的代碼笨觅。
Scope.prototype.$digest=function(){
var self = this;
var oldValue,newValue;
for(var i=0;i<this.$$watchers.length;i++){
oldValue = this.$$watchers[i].last;
newValue = this.$$watchers[i].watchFn(self)
if(oldValue!=newValue){
this.$$watchers[i].last = newValue;
this.$$watchers[i].listenFn();//注意這里
}
}
}
完善一下吧拦耐,在調(diào)用listenFn的時(shí)候把數(shù)據(jù)傳進(jìn)去,改成這樣:
this.$$watchers[i].listenFn(newValue,oldValue,self);
其實(shí)從這個(gè)角度來看见剩,回調(diào)函數(shù)幾乎就是JAVA中的接口:我們定義了watcher對(duì)象杀糯,我們規(guī)定了watcher對(duì)象要有watchFn和listenFn,我們規(guī)定了listenFn在符合條件的時(shí)候執(zhí)行苍苞,我們規(guī)定了listenFn函數(shù)需要的參數(shù)固翰,用戶只需要寫一個(gè)和我們規(guī)定的listenFn函數(shù)一模一樣的函數(shù)就可以使用。
還有一個(gè)問題羹呵,如果我有兩個(gè)watcher骂际,第一個(gè)watcher執(zhí)行完以后,數(shù)據(jù)是干凈的冈欢,可是第二個(gè)watcher又改變了屬性值歉铝,把數(shù)據(jù)變臟了,這時(shí)候第一個(gè)watcher并不知道凑耻,所以它的listenFn也不會(huì)執(zhí)行太示。
解決這個(gè)問題的思路是:為了防止某個(gè)listenFn在其他watcher不知情的時(shí)候操作其他的數(shù)據(jù),我可以設(shè)置一個(gè)標(biāo)志位拳话,只要listenFn被執(zhí)行過一次先匪,那么這個(gè)標(biāo)志位就是臟的,當(dāng)digest結(jié)束后弃衍,如果這個(gè)標(biāo)志位是臟的呀非,那么就說明在digest的時(shí)候執(zhí)行過listenFn,也許這個(gè)listenFn操作了不該操作的數(shù)據(jù),于是就要再執(zhí)行一次digest岸裙。
這樣看來猖败,先把$digest方法改名為$digestOnce比較好。
Scope.prototype.$digestOnce=function(){
var self = this;
var oldValue,newValue,dirty;
for(var i=0;i<this.$$watchers.length;i++){
oldValue = this.$$watchers[i].last;
newValue = this.$$watchers[i].watchFn(self)
if(oldValue!=newValue){
this.$$watchers[i].last = newValue;
this.$$watchers[i].listenFn(newValue,oldValue,self);
dirty=true;
}
}
return dirty;
}
然后外面再寫一個(gè)循環(huán)降允,來不斷檢測(cè)$digestOnce方法是否返回了dirty恩闻。
Scope.prototype.$digest=function(){
var dirty;
do {
dirty = this.$digestOnce();
} while (dirty);
}
寫一個(gè)測(cè)試案例跑一下試試:
it('digest循環(huán)', function() {
var i=0;
var j=0;
scope.name='wangji';
scope.age=22;
var watchFn1 = function(scope){
return scope.name
};
var listenFn1 = function(newvalue,oldvalue,scope){
console.log('第'+i+'次執(zhí)行watchFn1');
console.log('oldvalue:'+oldvalue);
console.log('newvalue:'+newvalue);
i++;
}
var watchFn2 = function(scope){
return scope.age
};
var listenFn2 = function(newvalue,oldvalue,scope){
console.log('第'+j+'次執(zhí)行watchFn2');
console.log('oldvalue:'+oldvalue);
console.log('newvalue:'+newvalue);
scope.name='hahaha';
j++;
}
scope.$watch(watchFn1,listenFn1);
scope.$watch(watchFn2,listenFn2);
scope.$digest();
});
能夠如期執(zhí)行: