Javascript 评估的增量操作顺序

Javascript increment operation order of evaluation

我知道 postfix/prefix increment/decrement 操作员的工作。而在javascript中,这似乎没有什么不同。

虽然我可以很容易地猜到这一行的结果:

var foo = 10; console.log(foo, ++foo, foo, foo++, foo); 
// output: 10 11 11 11 12

as ++ 运算符出现在单独的表达式中。

它变得有点复杂,因为这些运算符出现在同一个表达式中:

var foo = 10; console.log(foo, ++foo + foo++, foo);
// output[1]: 10 22 12
// Nothing unexpected assuming LTR evaluation

var foo = 10; console.log(foo, foo++ + ++foo, foo);
// output[2]: 10 22 12
// What? Ordering is now different but we have the same output.
// Maybe value of foo is evaluated lazily...

var foo = 10; console.log(foo, foo + ++foo, foo);
// output[3]: 10 21 11
// What?! So first 'foo' is evaluated before the increment?

我的问题是,Javascript(在本例中为 V8,正如我在 Chrome 中测试的那样)如何以不同方式评估第二个和第三个示例中的加法表达式?

为什么 foo 最终的评估结果与 foo++ 不同。后缀 ++ 不应该在表达式之后递增并且只在表达式内计算为 foo 吗?

var foo = 10; console.log(foo, ++foo + foo++, foo);

++foo + foo++
   11 + 11

预递增将 foo 设置为 11,然后再次将其添加到 foo,它仍然是 11,在 foo 再次递增之前评估为 22。

var foo = 10; console.log(foo, foo++ + ++foo, foo);

foo++ + ++foo
10    +    12

当我们到达 ++foo 时,该值已经与 foo++ 相关

var foo = 10; console.log(foo, foo + ++foo, foo);

foo + ++foo
10  +   11

foo 在我们将它添加到 foo 之前递增,因此给我们 10 + 11

摘要

基本上这完全取决于将它们加在一起时 foo 的当前值。

看看:

foo++ + ++foo

在心里改写为:

foo++ →
    addition_lhs = foo  // addition_lhs == 10
    foo += 1            // foo == 11
++foo →
    foo += 1            // foo == 12
    addition_rhs = foo  // addition_rhs == 12

addition_lhs + addition_rhs == 10 + 12 == 22

foo + ++foo

foo →
    addition_lhs = foo  // addition_lhs == 10
++foo →
    foo += 1            // foo == 11
    addition_rhs = foo  // addition_rhs == 11

addition_lhs + addition_rhs == 10 + 11 == 21

所以一切都是从左到右计算的,包括递增。

要理解的关键规则是,在 JavaScript 中执行 整个 左侧 (LHS),并在任何操作完成之前记住值右侧 (RHS)。

您可以通过 reading the standard 确认评估顺序,或者只是在表达式中放置一个运行时错误,然后看看会发生什么:

alert(1) + alert(2) + (function () { throw Error(); })() + alert(3)

请理解,当您使用 foo++ 时,您是在告诉 "compiler":将其推入堆栈后,将其递增。当您使用 ++foo 时,您是在告诉另一种方式:递增它然后将其推入堆栈。 ++ 运算符优先于 +,因为 "compiler" 以这种方式读取表达式 (foo++)+(++foo)