自制前端框架Web前端之路让前端飞

自制前端框架Day20.$apply和$eval的实现

2017-06-22  本文已影响9人  蚊子爸爸

$eval是什么

$eval可以在scope的上下文环境里执行一段代码。JS中普通的eval函数可以传入一段字符串,并且以window为上下文执行这段字符串。可是在angular中,$eval需要传入一个函数,并且以这个Scope为上下文执行这段函数,其实这很简单,就是一个普通的接口。看一段测试案例:

   it('$eval', function() {
        scope.a = 100;
        scope.$eval(function(scope){
            scope.a = 200;
        })
        expect(scope.a).toBe(200);
    });

这明显是一个接口,scope定义好的,格式就必须是这个格式。

Scope.prototype.$eval=function(expr,local){
    return expr(this,local);
}

为什么不用call来做$eval这个功能?

因为call是只有function才有的方法,普通对象没有,Scope就是一个普通对象。

$apply是什么

$apply这个方法简直是用angular的人都知道。它实际上做的事情是:
$apply接受一个function作为参数,在内部用$eval执行这个function,然后执行$digest刷新scope。

Scope.prototype.$apply=function(expr){
   return this.$eval(expr);
   this.$digest();//这一行不会被调用
}

看上面的代码,$digest是不会被调用的。可以用trycatch语句来解决:

Scope.prototype.$apply=function(expr){
    try {
        return this.$eval(expr);
    } finally{
        this.$digest();
    }
}

写一个测试案例试试:

 it('$apply', function() {
        var counter = 0;
        scope.name='wangji';
        var watchFn = function(scope){
            return scope.name
        };
        var listenFn = function(newvalue,oldvalue,scope){
           counter++;
        }
        scope.$watch(watchFn,listenFn);
        expect(counter).toBe(0);
        scope.$digest();
        expect(counter).toBe(1);
        scope.$apply(function(scope){
            scope.name='noname';
        })
        expect(counter).toBe(2);
    });

测试顺利通过。

舒服
上一篇 下一篇

猜你喜欢

热点阅读