JavaScript自增运算的求值顺序

7
我可以理解后缀/前缀自增/自减运算符的作用。在Javascript中,这似乎没有什么不同。
虽然我可以轻松猜测出这行代码的结果:
var foo = 10; console.log(foo, ++foo, foo, foo++, foo); 
// output: 10 11 11 11 12

++运算符出现在不同的表达式中时,它很容易理解。

但当这些运算符出现在同一表达式中时,情况会变得有些复杂:

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中测试了这些)如何以不同的方式评估第2个和第3个示例中的加法表达式?

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


我相信你所描述的行为表明在JavaScript中,加法是左结合的。这意味着left_expression + right_expression中的左表达式首先被评估。我相信增量运算符的行为符合您的期望。 - Frank Bryce
3个回答

8

只需要看一下:

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)执行任何操作。
您可以通过阅读标准来确认评估顺序,或者在表达式中放置运行时错误并查看发生了什么:
alert(1) + alert(2) + (function () { throw Error(); })() + alert(3)

1
所以我只需要知道增量发生在子表达式之后(在a之后,然后在a + b中的b之后),而不是整个表达式之后。 有道理。谢谢! - ntpl

2
了解当您使用foo++时,您正在告诉“编译器”:在将其推送到堆栈后,递增它。当您使用++foo时,您是在另一种方式上告诉的:先递增它,然后将其推送到堆栈。 ++运算符优先于+,因为“编译器”以这种方式读取表达式(foo++)+(++foo)

1

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

变量foo的值为10;打印出foo的值,以及++foo + foo++和foo的值。
++foo + foo++
   11 + 11

预增将foo设置为11,然后将其再次添加到仍为11的foo中,计算结果为22,然后再次增加foo。

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加到自身之前,先对其进行了递增操作,因此得到的结果是10 + 11。

摘要

基本上,这取决于将它们加在一起时foo的当前值是多少。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接