自制前端框架Day15 写写scope放松一下

写在前面

之前写博客是为了记录自己的开发过程,没指望有人看,所以写的非常凌乱。没想到的是在这些日子里,竟然会有其他人看我的博客并给我评论留言,我感到受宠若惊。所以我要求自己写博客要写的更容易让别人看懂,把自己的所想所得分享出去,如果有人看了我的博客,我希望的文字能对得起别人花费的时间。

前端框架是什么

其实前端框架做的事情都一样,无非是解决了如何用数据来渲染页面的问题:在我看来,无论react还是vue还是angular,其实都是controller+view。
拿我最熟悉的angular来说,数据与页面的绑定就是scope与compile的绑定。
之前写表达式解析部分写的头晕,决定换换脑子,写写scope。

scope的本质

scope其实就是一个普通对象,只不过上面封装了很多方法而已。

scope的数据监测机制

在angular的scope中,有两个部分是数据监测的关键,$watch和$digest。我目前不清楚vue的数据变化监测是什么机制,但是angular的是脏值监测,本质是给scope对象上增加watcher。

watcher是什么

watcher监控scope的某一个属性,并且当属性变化的时候执行回调函数。

$digest()是什么

digest负责把每一个watcher都检查并且运行一次。

今天先决定写这个部分。

在scope的对象上有很多watcher,所以要有一个地方存放这些watcher。

function Scope(){
    this.$$watchers=[]
}

scope有$watch函数,这个函数接受两个参数,第一个参数用于指定该watcher监听的属性,第二个是属性变化的时候执行的回调函数。

Scope.prototype.$watch=function(watchFn,listenFn){
    var watcher = {
        watchFn:watchFn,
        listenFn:listenFn
    }
    this.$$watchers.push(watcher);
}

$digest是用来执行所有watcher的listen方法,也很简单,遍历一下,执行就可以

Scope.prototype.$digest=function(){
    for(var i=0;i<this.$$watchers.length;i++){
        this.$$watchers[i].listenFn();
    }
}

写一个测试案例试试看:

describe('scope', function() {
    var scope;
    beforeEach(function(){
        scope=new Scope()
    })
    it('scope可以赋值', function() {
        scope.name='wangji'
        expect(scope.name).toBe('wangji');
    });
     it('scope的watch和digest方法执行正常', function() {
        var watchFn=function(){
            return 'name'
        }
        var listenFn=jasmine.createSpy();
        scope.$watch(watchFn,listenFn);
        scope.$digest();
        expect(listenFn).toHaveBeenCalled();
    });
});
顺利执行

watcher的实现就是典型的一种观察者模式

watcher有两个方法,一个是watchFn,一个是listenFn。watchFn用于获取scope上某一个属性的值:

watchFn=function(scope){
    return scope.id//这个watcher用于监听scope.id的值
}

listenFn是一个回调函数,这样一来就是很典型的观察者模式:一个方法用来监听某个对象的值,另一个方法是当监听到相应动作时候执行。

脏值检测的实现

每一个watcher既然能获取scope上的一个属性值,那么应该也可以保存上次的值。然后运行一次digest,把每一个watcher跑一次,如果这次拿到的值和上次保存的值不同,说明值是脏的,就可以运行listenFn回调函数,典型的观察者模式。

function Scope(){
    this.$$watchers=[]
}
Scope.prototype.$watch=function(watchFn,listenFn){
    var watcher = {
        watchFn:watchFn,
        listenFn:listenFn,
        last:''
    }
    this.$$watchers.push(watcher);
}
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();
        }
    }
}

执行以下案例看看效果

    it('脏值检测',function() {
        scope.id=2;
        var watchFn=function(scope){
            return scope.id;
        }
        var listenFn=function(){
              console.log('listen!')
        }
        scope.$watch(watchFn,listenFn);
        scope.$digest();
    })

运行$digest方法时,期望中是这样的:
watcher的last值最初是空的,调用watchFn后拿到id属性的值,是2,进行对比,不相等,然后执行了listenFn,打印出listen!这句话。同时,watcher的last被设置为新值,也就是2.
来运行一下试试:

旧值和新值确实不相等
last已经变成最新值
打印出了语句,说明listenFn执行了

没问题!那么再运行一次$digest的话,应该不会再打印listen了,因为经过第一次digest以后,watcher的last属性被赋值为最新值,所以值不再脏了,也就不再运行listenFn了。

执行两次digest,只运行了一次listenFn

完成,这就是脏值检测的核心。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容