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

时间:2013-02-14 13:39:01

标签: javascript angularjs

我知道只要Watchers中的某些内容在AngularJS中发生变化,就会计算Observers$scope。但无法理解两者之间究竟有什么区别。

我最初的理解是Observers是针对角度表达式计算的,这些条件是HTML端的条件,执行Watchers函数时执行$scope.$watch()。我在想什么?

4 个答案:

答案 0 :(得分:604)

$observe() Attributes对象上的一种方法,因此,它只能用于观察/观察DOM属性的值更改。它仅在指令内使用/调用。需要观察/观察包含插值的DOM属性时使用$ observe(即{{}})。
例如,attr1="Name: {{name}}",然后在指令中:attrs.$observe('attr1', ...)
(如果你尝试scope.$watch(attrs.attr1, ...)它会因{{}}而无效 - 你将获得undefined。)使用$ watch来获取其他所有内容。

$watch() 更复杂。它可以观察/观察“表达式”,其中表达式可以是函数或字符串。如果表达式是一个字符串,则它是$parse'd(即,被评估为Angular expression)到函数中。 (每个摘要周期都会调用此函数。)字符串表达式不能包含{{}}。 $ watch是Scope对象上的一个方法,因此可以在任何有权访问范围对象的地方使用/调用它,因此在

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

因为字符串被评估为Angular表达式,所以当您想要观察/观察模型/范围属性时,通常会使用$ watch。例如,attr1="myModel.some_prop",然后在控制器或链接函数中:scope.$watch('myModel.some_prop', ...)scope.$watch(attrs.attr1, ...)(或scope.$watch(attrs['attr1'], ...))。
(如果您尝试attrs.$observe('attr1'),您将获得字符串myModel.some_prop,这可能不是您想要的。)

正如@ PrimosK的答案评论所述,每digest cycle次检查所有$ observes和$ watch。

具有隔离范围的指令更复杂。如果使用'@'语法,您可以$ observe 或$ watch 包含插值的DOM属性(即{{}})。 (它与$ watch一起使用的原因是因为'@'语法为我们执行interpolation,因此$ watch会看到没有{{}}的字符串。)为了更容易记住在哪个时使用,我建议在这种情况下使用$ observe。

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

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

查看控制台日志,查看链接函数中$ observe和$ watch之间的差异。然后单击该链接,查看由Click处理程序进行的属性更改触发了哪些$ observes和$ watches。

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

有时你不需要$ observe或$ watch。例如,如果您的属性包含数字或布尔值(不是字符串),则只需评估一次:attr1="22",然后在您的链接函数中进行评估:var count = scope.$eval(attrs.attr1)。如果它只是一个常量字符串 - attr1="my string" - 那么只需在你的指令中使用attrs.attr1(不需要$ eval())。

另请参阅Vojta's google group post关于$ watch表达式。

答案 1 :(得分:23)

如果我理解你的问题是正确的,那么如果你使用$watch注册听众回调,或者如果你使用$observe注册,那么你会问有什么不同。

执行$watch时会触发注册$digest的回调。

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


Inside指令你可以用非常相似的方式使用它们:

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

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

答案 2 :(得分:1)

我认为这很明显:

  • $ observe用于链接指令功能。
  • $ watch用于范围,以观察其值的任何变化。

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

$observe/$watch(value : string, callback : function);
  • value :始终是对被监视元素的字符串引用(作用域变量的名称或要监视的指令属性的名称)
  • 回调:表格function (oldValue, newValue)
  • 的执行功能

我已经制作了plunker,所以你可以真正掌握它们的利用率。我使用了Chameleon的比喻,以便更容易想象。

答案 3 :(得分:0)

为什么$观察与$ watch不同?

对watchExpression进行求值并与每个摘要()循环的前一个值进行比较,如果watchExpression值发生变化,则会调用watch函数。

$ observe特定于观察插值。如果对指令的属性值进行插值,例如dir-attr="{{ scopeVar }}",则只有在设置插值时才会调用observe函数(因此当$ digest已经确定需要进行更新时)。基本上已经有一个用于插值的观察器,$ observe函数可以捎带它。

参见$ observe&amp;在compile.js

中设置$