角度表达式中的多个语句

Cyr*_* Ka 7 angularjs

我正在玩Angularjs,可能我在滥用它.我使用分号在这样的角度表达式中有几个语句(jsFiddle):

<tr ng-repeat="i in [1, 2, 3, 4]">
  <td>i = {{ m = k; k = j; j = i + 1; i}}</td>
  <td>j = {{j}}</td>
  <td>k = {{k}}</td>
  <td>m = {{m}}</td>
</tr>
Run Code Online (Sandbox Code Playgroud)

起初,我认为在计算之前k会有值,但显然它不会像这样工作.结果是:ji+1

i = 1   j = 2   k = 2   m = 2
i = 2   j = 3   k = 3   m = 3
i = 3   j = 4   k = 4   m = 4
i = 4   j = 5   k = 5   m = 5
Run Code Online (Sandbox Code Playgroud)

因此很明显,分配jkkm,并不意味着值复制,但这些名称绑定在一起.我能理解.但是如果我删除显示k(jsFiddle)值的行,会发生奇怪的事情:

<tr ng-repeat="i in [1, 2, 3, 4]">
  <td>i = {{ m = k; k = j; j = i + 1; i}}</td>
  <td>j = {{j}}</td>
  <td>m = {{m}}</td>
</tr>
Run Code Online (Sandbox Code Playgroud)

我正在获得:

i = 1   j = 2   m =
i = 2   j = 3   m =
i = 3   j = 4   m =
i = 4   j = 5   m =
Run Code Online (Sandbox Code Playgroud)

也就是说m,尽管它被绑定j(通过k),但不包含任何值.它可能是因为k它本身没有被评估.

我的问题是:它不是AngularJS中的错误吗?当然k,即使它没有直接显示,也应该评估它是否在绑定链中.或者我误解了什么?

我知道它可能不是使用AngularJS的惯用方法,但我想真正理解表达式引擎,我无法解释这种行为.

ana*_*ker 8

这里有几个相互作用的问题.

首先,你的陈述是向后排序的:你在设置j之前设置k = j,这导致它未被定义.

其次,更重要的是,不应使用插值表达式("{{}}"中的表达式)来改变范围的状态.这有一个很好的理由:

插值和手表

插值的工作方式是,当它编译你的html时,angular会scope.$watch在每个插值表达式上注册a .

但是这些观察到的表达式可以在摘要期间多次执行:每当侦听器修改范围时,它会使角度再次通过该范围上的监视.出于这个原因,观看的表达式确实应该是"幂等的":即,它们应该没有副作用/导致状态没有变化.这是来自以下文档$watch:

每次调用$ digest()时都会调用watchExpression,并且应该返回将要监视的值.(由于$ digest()在检测到更改时重新运行,因此watchExpression可以每$ digest()执行多次,并且应该是幂等的.)

跟踪示例

具体来说,这是你的例子中发生的事情.首先,它与转发器无关.每个ng-repeat项目都有自己的范围,所以这里发生的事情等同于这个更简单的例子:

<div ng-app>
    {{ i = 42 }}<br>
    i = {{ m = k; k = j; j = i+1; i }}<br>
    j = {{j}}<br>
    k = {{k}}<br>
    m = {{m}}<br>
</div>
Run Code Online (Sandbox Code Playgroud)

(这是小提琴)

摘要的进行如下:

  1. 评估{{ i = 42 }}设置scope.i为42,并在文档中显示"42".但是,由于范围已经改变,所以还设置了" "标志,这意味着我们将再次循环通过手表(参见下面的步骤5)
  2. 评估{{ m = k; k = j; j = i+1; i }}scope.mscope.kto undefined,以及scope.j43,并在文档中显示"42".
  3. 评估{{ j }}在文档中显示"43".
  4. 评估{{ k }}然后{{ m }}在文档中只显示"",因为它们当前未定义.
  5. 现在,由于设置了脏标志,我们重复所有这些手表; 这次,当我们跑步时{{ m = k; k = j; j = i+1; i }},k = j起作用,因为j存在; 所以k被赋值为43.
  6. 当我们到达{{ k }}这个时候,它的值已从undefined更改为2,因此脏标志再次设置,但现在文档显示"k = 2".但是,{{ m }}仍然未定义.
  7. 就像5-6一样,我们再次通过手表,这一次,{{ m = k; k = j; j = i+1; i }}导致m被设置为43.

切线:双加工手表?

切向地,我在浏览摘要代码时遇到了一个有趣的事情:看起来脏标志在第一次通过手表时始终设置为true,因为从未检查过的手表没有记录"最后"值.看起来这样会导致大量不必要的双重处理.即使观察值是{{2}}之类的常数,这似乎也是正确的.我在这里误解了什么吗?