Javascript中的预增量

nha*_*123 11 javascript pre-increment

我刚刚在Javascript中遇到了关于预增量的'功能'.在我使用的所有其他语言中,它就像我认为的那样.例如在C++中:

#include <iostream>

int main()
{
    int i = 0;

    i += ++i;

    std::cout << i << std::endl; // Outputs 2.
}
Run Code Online (Sandbox Code Playgroud)

因此,++i不会复制变量,因此输出为2.

在PHP中相同:

<?php

$i = 0;

$i += ++$i;

echo $i; // Outputs 2.

Run Code Online (Sandbox Code Playgroud)

但是,在Javascript中:

var i = 0;

i += ++i;

console.log(i); // Outputs 1.
Run Code Online (Sandbox Code Playgroud)

所以它看起来像在Javascript中,它复制i并且不引用变量.这是故意的,如果是,为什么?

Ama*_*dan 7

来自EcmaScript标准:

11.4.4前缀增量运算符

生产UnaryExpression:++ UnaryExpression的计算方法如下:

  1. 设expr是评估UnaryExpression的结果.
  2. 如果满足以下条件,则抛出SyntaxError异常:
    • Type(expr)是Reference为true
    • IsStrictReference(expr)是真的
    • Type(GetBase(expr))是环境记录
    • GetReferencedName(expr)是"eval"或"arguments"
  3. 设oldValue为ToNumber(GetValue(expr)).
  4. 设newval是将值1添加到oldValue的结果,使用与+运算符相同的规则(见11.6.3).
  5. 调用PutValue(expr,newValue).
  6. 返回newValue.

11.13.2复合赋值(op =)

生产AssignmentExpression:LeftHandSideExpression AssignmentOperator AssignmentExpression,其中AssignmentOperator是@ =和@代表上面指出的一个运算符,评估如下:

  1. 让lref成为评估LeftHandSideExpression的结果.
  2. 设lval为GetValue(lref).
  3. 让rref成为评估AssignmentExpression的结果.
  4. 设rval为GetValue(rref).
  5. 设r是将operator @应用于lval和rval的结果.
  6. 如果满足以下条件,则抛出SyntaxError异常:
    • Type(lref)是Reference为true
    • IsStrictReference(lref)是真的
    • Type(GetBase(lref))是环境记录
    • GetReferencedName(lref)是"eval"或"arguments"
  7. 调用PutValue(lref,r)

因此,var i = 0; i += ++i是:

i = 0;
lvalue = value(i), which is 0;
rvalue = value(++i), which is: increment i, then value of i (1);
thus, rvalue = 1;
i = lvalue (0) + rvalue (1), which is 1.
Run Code Online (Sandbox Code Playgroud)

完全按照规范.

但是,在C++中,这被明确定义为未定义的行为,因此在不同的编译器上,您可能也会获得1.或99.或者它可能会使您的计算机着火.所有这些都是符合标准的编译器.因此,大多数人会建议您只在声明中使用一次/后递增变量.