首页 文章

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

提问于
浏览
371

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

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

4 回答

  • 0

    $observe()Attributes对象上的方法,因此,它只能用于观察/观察DOM属性的值更改 . 它仅在指令内使用/调用 . 需要观察/观察包含插值的DOM属性时使用$ observe(即{{}}) .
    例如, attr1="Name: {{name}}" ,然后在指令中: attrs.$observe('attr1', ...) .
    (如果你试试 scope.$watch(attrs.attr1, ...) 它赢了't work because of the {{}}s -- you' ll得到 undefined . )使用$ watch获取其他所有内容 .

    $watch() 更复杂 . 它可以观察/观察"expression",其中表达式可以是函数或字符串 . 如果表达式是一个字符串,则它是$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属性(即{{}} 's). (The reason it works with $watch is because the ' @'语法对我们来说是interpolation,因此$ watch会看到没有{{}}的字符串 . )为了更容易记住何时使用,我建议在这种情况下使用$ observe .

    为了帮助测试所有这些,我编写了一个定义两个指令的Plunker . 一个( d1 )不创建新范围,另一个( d2 )创建隔离范围 . 每个指令具有相同的六个属性 . 每个属性都是$ observe 'd and $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 .

    请注意,当链接函数运行时,包含{{}} 's are not evaluated yet (so if you try to examine the attributes, you' ll的任何属性都会得到 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表达式 .

  • 23

    如果我理解你的问题是正确的,那么如果你用 $watch 注册监听器回调或者如果你用 $observe 注册,那么你会问有什么区别 .

    执行 $digest 时,将触发 $watch 注册的回调 .

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


    在内部指令中,您可以以非常类似的方式使用它们:

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

    要么

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

    我认为这很明显:

    • $ observe用于链接指令的功能 .

    • $ watch用于范围以观察其值的任何变化 .

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

    $observe/$watch(value : string, callback : function);
    
    • value :始终是对被监视元素的字符串引用(要监视的范围's variable or the name of the directive' s属性的名称)

    • callback :表单执行的函数 function (oldValue, newValue)

    我已经制作了一个plunker,所以你实际上可以掌握它们的利用率 . 我使用了变色龙的类比,以便更容易拍照 .

  • 1

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

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

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

    请参阅compile.js中的$ observe&$ set

相关问题