AngularJS:$ observe和$ watch方法之间的区别

我知道,只要AngularJS中$scope某些内容发生变化,Watcher和Observers被计算出来。 但是不明白这两者之间究竟有什么区别。

我最初的理解是Observers被计算为angular度expression式,这是HTML端的条件,当$scope.$watch()函数被执行时, Watchers被执行。 我是否正确思考?

$ observe()是Attributes对象上的一个方法,因此它只能用于观察/观察DOM属性的值更改。 它只用于/叫内部指令。 当需要观察/观察包含插值的DOM属性(即{{}})时,请使用$ observe。
例如, attr1="Name: {{name}}" ,然后在一个指令中: attrs.$observe('attr1', ...)
(如果你尝试使用scope.$watch(attrs.attr1, ...) ,它将不会工作,因为{{}} – 你会得到undefined 。)使用$ watch scope.$watch(attrs.attr1, ...)其他事情。

$ watch()更复杂。 它可以观察/观察“expression式”,其中expression式可以是函数或string。 如果expression式是一个string,则它是$ parse'd (即,作为一个Angularexpression式求值)到一个函数中。 (这个函数被称为每个摘要循环。)stringexpression式不能包含{{}}。 $ watch是Scope对象的一个​​方法,所以只要你有权访问一个scope对象,就可以使用它

  • 一个控制器 – 任何控制器 – 一个通过ng-view,ng-controller或一个指令控制器创build的控制器
  • 一个指令中的链接函数,因为它也可以访问范围

因为string被评估为Angularexpression式,所以当你想要观察/观察一个模型/范围属性时,经常使用$ watch。 例如, attr1="myModel.some_prop" ,然后在控制器或链接函数中: scope.$watch('myModel.some_prop', ...)scope.$watch(attrs.attr1, ...) (或scope.$watch(attrs['attr1'], ...) )。
(如果你尝试attrs.$observe('attr1')你会得到stringmyModel.some_prop ,这可能不是你想要的。)

正如@ PrimosK的回答中所讨论的那样,每个摘要周期都会检查所有$ observes和$ watch。

隔离范围指令更复杂。 如果使用'@'语法,则可以$ observe 或$观察包含插值的DOM属性(即{{}})。 (与$ watch一起工作的原因是因为'@'语法为我们插值 ,因此$ watch会看到一个没有{{}}的string。)为了更容易记住使用什么时候,我build议使用$也观察这种情况。

为了帮助testing所有这些,我写了一个定义了两个指令的Plunker 。 一个( d1 )不创build一个新的范围,另一个( d2 )创build一个隔离范围。 每个指令具有相同的六个属性。 每个属性都是$ observe'd和$ watch'ed。

 <div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'" attr5="a_string" attr6="{{1+aNumber}}"></div> 

查看控制台日志,查看链接function中$ observe和$ watch之间的差异。 然后点击链接,看看哪些$ observes和$ watch是由点击处理程序所做的属性更改触发的。

请注意,链接函数运行时,任何包含{{}}的属性都不会被评估(因此如果您尝试检查属性,则会得到undefined的属性)。 查看插值的唯一方法是使用$ observe(或$ watch,如果使用隔离范围和'@')。 因此,获取这些属性的值是一个asynchronous操作。 (这就是为什么我们需要$ observe和$ watch函数。)

有时你不需要$观察或$手表。 例如,如果你的属性包含一个数字或一个布尔值(不是string),只需计算一次: attr1="22" ,然后在你的链接函数中: var count = scope.$eval(attrs.attr1) 。 如果它只是一个常量string – attr1="my string" – 那么只需在你的指令中使用attrs.attr1 (不需要$ eval())。

另请参阅Vojta关于$ watchexpression式的google群组文章 。

如果我正确理解你的问题,你要问的是,如果你用$watch注册监听器callback,或者你用$observe做注册,

执行$digest时会触发注册了$watchcallback函数。 请参阅文档了解更多信息。

当包含插值的属性的值更改(例如attr="{{notJetInterpolated}}" )时,将调用注册到$observecallback。


在内部指令中,你可以用非常相似的方式使用它们两个:

  attrs.$observe('attrYouWatch', function() { // body }); 

要么

  scope.$watch(attrs['attrYouWatch'], function() { // body }); 

我觉得这很明显:

  • $ observe用于指令的链接function。
  • $ watch用于范围内观察其值的任何变化。

请记住 :这个函数有两个参数,

 $observe/$watch(value : string, callback : function); 
  • value :始终是对watched元素的string引用(作用域variables的名称或要监视的指令属性的名称)
  • callback :要执行的function (oldValue, newValue)

我做了一个笨蛋 ,所以你可以实际掌握它们的使用情况。 我已经使用了变色龙的比喻来使绘画更容易。