自制前端框架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);
});
测试顺利通过。
