初识angularJS

275 阅读2分钟

公司的项目是用angular写的,慢慢开始接触angular框架

$Scope

Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带。

Scope 是一个对象,有可用的方法和属性。

Scope 可应用在视图和控制器上。

脏数据检查(Dirty checking)

angularJS监测对象变化不是像vue.js那样通过Object.defineproperty这种接口,而是在某些情况下制定策略,通过复制保存一份数据,进行快照对比,来监测变化。

$watch

在digest执行时,如果watch观察的的value与上一次执行时不一样时,就会被触发。

AngularJS内部的watch实现了页面随model的及时更新。

$watch方法在用的时候主要是手动的监听一个对象,但对象发生变化时触发某个事件。

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

$digest()

在digest循环中,watchers会被触发。当一个watcher被触发时,AngularJS会检测scope模型,如何它发生了变化那么关联到该watcher的回调函数就会被调用。

那么,$digest循环是在什么时候以各种方式开始的?

在调用了scope.scope.digest()后,digest循环就开始了。假设你在一个ngclick指令对应的handler函数中更改了scope中的一条数据,此时AngularJS会自动地通过调用digest循环就开始了。假设你在一个ng-click指令对应的handler函数中更改了scope中的一条数据,此时AngularJS会自动地通过调用digest()来触发一轮digest循环。当digest循环。当digest循环开始后,它会触发每个watcher。这些watchers会检查scope中的当前model值是否和上一次计算得到的model值不同。如果不同,那么对应的回调函数会被执行。调用该函数的结果,就是view中的表达式内容(译注:诸如{{ aModel }})会被更新。除了ng-click指令,还有一些其它的built-in指令以及服务来让你更改models(比如ng-model,timeout)和自动触发一次timeout等)和自动触发一次digest循环。

$digest循环会运行多少次?

答案是digest循环不会只运行一次。在当前的一次循环结束后,它会再执行一次循环用来检查是否有models发生了变化。这就是脏检查(Dirty Checking),它用来处理在listener函数被执行时可能引起的model变化。因此,digest循环会持续运行直到model不再发生变化,或者digest循环会持续运行直到model不再发生变化,或者digest循环的次数达到了10次。因此,尽可能地不要在listener函数中修改model。

digest循环最少也会运行两次,即使在listener函数中并没有改变任何model。正如上面讨论的那样,它会多运行一次来确保models没有变化。

$apply()

scope.scope.apply()会自动地调用rootScope.rootScope.digest()。apply()方法有两种形式。第一种会接受一个function作为参数,执行该function并且触发一轮apply()方法有两种形式。第一种会接受一个function作为参数,执行该function并且触发一轮digest循环。第二种会不接受任何参数,只是触发一轮$digest循环。

什么时候手动调用$apply()方法?

如果AngularJS总是将我们的代码wrap到一个function中并传入apply(),以此来开始一轮apply(),以此来开始一轮digest循环,那么什么时候才需要我们手动地调用apply()方法呢?实际上,AngularJS对此有着非常明确的要求,就是它只负责对发生于AngularJS上下文环境中的变更会做出自动地响应(即,在apply()方法中发生的对于models的更改)。AngularJS的built-in指令就是这样做的,所以任何的model变更都会被反映到view中。但是,如果你在AngularJS上下文之外的任何地方修改了model,那么你就需要通过手动调用$apply()来通知AngularJS。这就像告诉AngularJS,你修改了一些models,希望AngularJS帮你触发watchers来做出正确的响应。

比如,如果你使用了JavaScript中的setTimeout()来更新一个scope model,那么AngularJS就没有办法知道你更改了什么。这种情况下,调用apply()就是你的责任了,通过调用它来触发一轮apply()就是你的责任了,通过调用它来触发一轮digest循环。类似地,如果你有一个指令用来设置一个DOM事件listener并且在该listener中修改了一些models,那么你也需要通过手动调用$apply()来确保变更会被正确的反映到view中。