[英]AngularJS : Difference between the $observe and $watch methods
我知道AngularJS中$scope
中的某些更改会立即计算Watchers
和Observers
。 但是无法理解两者之间到底有什么区别。
我最初的理解是, Observers
是针对角度表达式计算的,这些角度表达式是HTML端的条件,在Watchers
执行$scope.$watch()
函数时执行。 我的想法是否正确?
$ observe()是Attributes对象上的一种方法,因此,它只能用于观察/监视DOM属性的值更改。 仅用于/调用内部指令。 当需要观察/观察包含插值的DOM属性(即{{}})时,请使用$ observe。
例如, attr1="Name: {{name}}"
,然后在指令中: attrs.$observe('attr1', ...)
。
(如果尝试使用scope.$watch(attrs.attr1, ...)
,则由于{{}}而无法正常工作-您将无法undefined
。)将$ watch用于其他所有内容。
$ watch()更复杂。 它可以观察/观察“表达式”,其中表达式可以是函数或字符串。 如果表达式是字符串,则将$ parse'd (即,作为Angular表达式求值)放入函数中。 (每个摘要周期都会调用此函数。)字符串表达式不能包含{{}}。 $ watch是Scope对象上的一种方法,因此可以在任何有权访问scope对象的地方使用/调用它,因此在
因为字符串是作为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
获得字符串myModel.some_prop
,这可能不是您想要的。)
如对@PrimosK答案的评论中所讨论的,每个摘要周期都会检查所有$ observes和$ watches。
具有单独作用域的指令更加复杂。 如果使用“ @”语法,则可以$ observ 或$ watch包含插值(即{{}})的DOM属性。 (它与$ watch一起使用的原因是因为'@'语法为我们进行了插值 ,因此$ watch看到的字符串中没有{{}}。)为了更容易记住何时使用哪个字符串,我建议使用$在这种情况下也要观察。
为了帮助测试所有这些,我编写了一个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之间的区别。 然后单击链接,查看单击处理程序所做的属性更改触发了哪些$ observes和$ watches。
请注意,当链接函数运行时,尚未评估任何包含{{}}的属性(因此,如果您尝试检查这些属性,则会得到undefined
)。 查看插值的唯一方法是使用$ observe(如果使用带'@'的隔离范围,则使用$ watch)。 因此,获取这些属性的值是异步操作。 (这就是为什么我们需要$ observe和$ watch函数。)
有时您不需要$ observe或$ watch。 例如,如果您的属性包含数字或布尔值(不是字符串),则只需对其进行一次评估: attr1="22"
,然后在例如您的链接函数中: var count = scope.$eval(attrs.attr1)
。 如果它只是一个常量字符串– attr1="my string"
–则只需在指令中使用attrs.attr1
(不需要$ eval())。
另请参见Vojta在Google网上论坛上发布的有关$ watch表达式的信息。
如果我对您的问题理解正确,那么您在问,如果您使用$watch
注册监听器回调,或者如果您使用$observe
监听,那有什么区别。
执行$digest
时会触发在$watch
注册的回调。
当包含插值的属性(例如attr="{{notJetInterpolated}}"
)的值发生更改时,将调用$observe
注册的回调。
内部指令可以以非常相似的方式使用它们:
attrs.$observe('attrYouWatch', function() {
// body
});
要么
scope.$watch(attrs['attrYouWatch'], function() {
// body
});
我认为这很明显:
请记住 :这两个函数都有两个参数,
$observe/$watch(value : string, callback : function);
function (oldValue, newValue)
要执行的function (oldValue, newValue)
我制造了一个塞子 ,因此您实际上可以了解它们的利用率。 我使用了变色龙类比,以使其更容易描绘。
为什么$ observe与$ watch不同?
评估watchExpression并将其与每个digest()周期的前一个值进行比较,如果watchExpression值发生变化,则会调用watch函数。
$ observe专门用于监视插值。 如果插入指令的属性值,例如dir-attr="{{ scopeVar }}"
,则仅在设置了插入值时(因此,在$ digest已经确定需要进行更新时),将调用observe函数。 基本上,已经有一个插值的监视程序,并且$ observe函数支持此操作。
请参见compile.js中的 $ observe和$ set
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.