深入理解Angularjs 脏值检测(2)

  • 一个监控函数,用于指定所关注的那部分数据。
  • 一个监听函数,用于在数据变更的时候接受提示。

作为一名Angular用户,一般来说,是监控一个表达式,而不是使用监控函数。监控表达式是一个字符串,比如说“user.firstName”,通常在数据绑定,指令的属性,或者JavaScript代码中指定,它被Angular解析和编译成一个监控函数。在这篇文章的后面部分我们会探讨这是如何做的。在这篇文章中,我们将使用稍微低级的方法直接提供监控功能。

为了实现$watch,我们需要存储注册过的所有监听器。我们在Scope构造函数上添加一个数组:

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

在Angular框架中,双美元符前缀$$表示这个变量被当作私有的来考虑,不应当在外部代码中调用。

现在我们可以定义$watch方法了。它接受两个函数作参数,把它们存储在$$watchers数组中。我们需要在每个Scope实例上存储这些函数,所以要把它放在Scope的原型上:

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

另外一面就是$digest函数。它执行了所有在作用域上注册过的监听器。我们来实现一个它的简化版,遍历所有监听器,调用它们的监听函数:

Scope.prototype.$digest = function() {
 _.forEach(this.$$watchers, function(watch) {
  watch.listenerFn();
 }); 
};

现在我们可以添加监听器,然后运行$digest了,这将会调用监听函数:

http://jsbin.com/oMaQoxa/2/embed?js,console

这些本身没什么大用,我们要的是能检测由监控函数指定的值是否确实变更了,然后调用监听函数。

脏值检测

如同上文所述,监听器的监听函数应当返回我们所关注的那部分数据的变化,通常,这部分数据就存在于作用域中。为了使得访问作用域更便利,在调用监控函数的时候,使用当前作用域作为实参。一个关注作用域上fiestName属性的监听器像这个样子:

function(scope) {
 return scope.firstName;
}

这是监控函数的一般形式:从作用域获取一些值,然后返回。

$digest函数的作用是调用这个监控函数,并且比较它返回的值和上一次返回值的差异。如果不相同,监听器就是脏的,它的监听函数就应当被调用。

想要这么做,$digest需要记住每个监控函数上次返回的值。既然我们现在已经为每个监听器创建过一个对象,只要把上一次的值存在这上面就行了。下面是检测每个监控函数值变更的$digest新实现:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/219.html