Javascript AngularJS:$observe 和 $watch 方法的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14876112/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 18:12:10  来源:igfitidea点击:

AngularJS : Difference between the $observe and $watch methods

javascriptangularjs

提问by Abilash

I know that both Watchersand Observersare computed as soon as something in $scopechanges in AngularJS. But couldn't understand what exactly is the difference between the two.

我知道,无论WatchersObservers就将计算在东西$scope在AngularJS变化。但无法理解两者之间究竟有什么区别。

My initial understanding is that Observersare computed for angular expressions which are conditions on the HTML side where as Watchersexecuted when $scope.$watch()function is executed. Am I thinking properly?

我最初的理解是Observers为角度表达式计算的,角度表达式是在Watchers执行$scope.$watch()函数时执行的 HTML 端的条件。我的想法正确吗?

回答by Mark Rajcok

$observe()is a method on the Attributesobject, and as such, it can only be used to observe/watch the value change of a DOM attribute. It is only used/called inside directives. Use $observe when you need to observe/watch a DOM attribute that contains interpolation (i.e., {{}}'s).
E.g., attr1="Name: {{name}}", then in a directive: attrs.$observe('attr1', ...).
(If you try scope.$watch(attrs.attr1, ...)it won't work because of the {{}}s -- you'll get undefined.) Use $watch for everything else.

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

$watch()is more complicated. It can observe/watch an "expression", where the expression can be either a function or a string. If the expression is a string, it is $parse'd (i.e., evaluated as an Angular expression) into a function. (It is this function that is called every digest cycle.) The string expression can not contain {{}}'s. $watch is a method on the Scopeobject, so it can be used/called wherever you have access to a scope object, hence in

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

  • a controller -- any controller -- one created via ng-view, ng-controller, or a directive controller
  • a linking function in a directive, since this has access to a scope as well
  • 控制器——任何控制器——通过 ng-view、ng-controller 或指令控制器创建的控制器
  • 指令中的链接函数,因为它也可以访问范围

Because strings are evaluated as Angular expressions, $watch is often used when you want to observe/watch a model/scope property. E.g., attr1="myModel.some_prop", then in a controller or link function: scope.$watch('myModel.some_prop', ...)or scope.$watch(attrs.attr1, ...)(or scope.$watch(attrs['attr1'], ...)).
(If you try attrs.$observe('attr1')you'll get the string myModel.some_prop, which is probably not what you want.)

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

As discussed in comments on @PrimosK's answer, all $observes and $watches are checked every digest cycle.

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

Directives with isolate scopes are more complicated. If the '@' syntax is used, you can $observe or $watcha DOM attribute that contains interpolation (i.e., {{}}'s). (The reason it works with $watch is because the '@' syntax does the interpolationfor us, hence $watch sees a string without {{}}'s.) To make it easier to remember which to use when, I suggest using $observe for this case also.

具有隔离作用域的指令更复杂。如果使用“@”语法,您可以 $observe或 $watch包含插值(即 {{}} 的)的 DOM 属性。(它与 $watch 一起使用的原因是因为 '@' 语法为我们做了插值,因此 $watch 看到一个没有 {{}} 的字符串。)为了更容易记住什么时候使用哪个,我建议使用$observe 也适用于这种情况。

To help test all of this, I wrote a Plunkerthat defines two directives. One (d1) does not create a new scope, the other (d2) creates an isolate scope. Each directive has the same six attributes. Each attribute is both $observe'd and $watch'ed.

为了帮助测试所有这些,我编写了一个定义两个指令的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>

Look at the console log to see the differences between $observe and $watch in the linking function. Then click the link and see which $observes and $watches are triggered by the property changes made by the click handler.

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

Notice that when the link function runs, any attributes that contain {{}}'s are not evaluated yet (so if you try to examine the attributes, you'll get undefined). The only way to see the interpolated values is to use $observe (or $watch if using an isolate scope with '@'). Therefore, getting the values of these attributes is an asynchronousoperation. (And this is why we need the $observe and $watch functions.)

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

Sometimes you don't need $observe or $watch. E.g., if your attribute contains a number or a boolean (not a string), just evaluate it once: attr1="22", then in, say, your linking function: var count = scope.$eval(attrs.attr1). If it is just a constant string – attr1="my string"– then just use attrs.attr1in your directive (no need for $eval()).

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

See also Vojta's google group postabout $watch expressions.

另请参阅Vojta关于 $watch 表达式的 google group 帖子

回答by PrimosK

If I understand your question right you are asking what is difference if you register listener callback with $watchor if you do it with $observe.

如果我正确理解您的问题,您会问$watch如果您使用$observe.

Callback registerd with $watchis fired when $digestis executed.

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

Callback registered with $observeare called when value changes of attributes that contain interpolation (e.g. attr="{{notJetInterpolated}}").

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



Inside directive you can use both of them on very similar way:

内部指令您可以以非常相似的方式使用它们:

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

or

或者

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

回答by vdegenne

I think this is pretty obvious :

我认为这很明显:

  • $observe is used in linking function of directives.
  • $watch is used on scope to watch any changing in its values.
  • $observe 用于指令的链接功能。
  • $watch 用于作用域以观察其值的任何变化。

Keep in mind: both the function has two arguments,

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

$observe/$watch(value : string, callback : function);
  • value: is always a string reference to the watched element (the name of a scope's variable or the name of the directive's attribute to be watched)
  • callback: the function to be executed of the form function (oldValue, newValue)
  • value:始终是对被监视元素的字符串引用(范围变量的名称或要监视的指令属性的名称)
  • callback: 表单要执行的函数function (oldValue, newValue)

I have made a plunker, so you can actually get a grasp on both their utilization. I have used the Chameleon analogy as to make it easier to picture.

我制作了一个plunker,因此您实际上可以掌握它们的使用情况。我使用了变色龙类比,以便更容易地描绘。

回答by Niko

Why is $observe different than $watch?

为什么 $observe 与 $watch 不同?

The watchExpression is evaluated and compared to the previous value each digest() cycle, if there's a change in the watchExpression value, the watch function is called.

watchExpression 被评估并与每个digest() 周期的前一个值进行比较,如果 watchExpression 值发生变化,则调用 watch 函数。

$observe is specific to watching for interpolated values. If a directive's attribute value is interpolated, eg dir-attr="{{ scopeVar }}", the observe function will only be called when the interpolated value is set (and therefore when $digest has already determined updates need to be made). Basically there's already a watcher for the interpolation, and the $observe function piggybacks off that.

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

See $observe & $set in compile.js

compile.js 中的$observe & $set