Pre increment in Javascript

≡放荡痞女 提交于 2019-12-18 13:06:11

问题


I've just encountered a 'feature' in Javascript regarding pre-increments. In all other languages I've used, it goes like I thought it would. E.g. in C++:

#include <iostream>

int main()
{
    int i = 0;

    i += ++i;

    std::cout << i << std::endl; // Outputs 2.
}

So, ++i doesn't make copy of the variable, hence the output is 2.

Same in PHP:

<?php

$i = 0;

$i += ++$i;

echo $i; // Outputs 2.

However, in Javascript:

var i = 0;

i += ++i;

console.log(i); // Outputs 1.

So it looks like that in Javascript, it makes copy of i and doesn't reference the variable. Is this intentional and if yes, why?


回答1:


From EcmaScript standard:

11.4.4 Prefix Increment Operator

The production UnaryExpression : ++ UnaryExpression is evaluated as follows:

  1. Let expr be the result of evaluating UnaryExpression.
  2. Throw a SyntaxError exception if the following conditions are all true: �
    • Type(expr) is Reference is true
    • IsStrictReference(expr) is true
    • Type(GetBase(expr)) is Environment Record
    • GetReferencedName(expr) is either "eval" or "arguments"
  3. Let oldValue be ToNumber(GetValue(expr)).
  4. Let newValue be the result of adding the value 1 to oldValue, using the same rules as for the + operator (see 11.6.3).
  5. Call PutValue(expr, newValue).
  6. Return newValue.

and

11.13.2 Compound Assignment ( op= )

The production AssignmentExpression : LeftHandSideExpression AssignmentOperator AssignmentExpression, where AssignmentOperator is @= and @ represents one of the operators indicated above, is evaluated as follows:

  1. Let lref be the result of evaluating LeftHandSideExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating AssignmentExpression.
  4. Let rval be GetValue(rref).
  5. Let r be the result of applying operator @ to lval and rval.
  6. Throw a SyntaxError exception if the following conditions are all true:
    • Type(lref) is Reference is true
    • IsStrictReference(lref) is true
    • Type(GetBase(lref)) is Environment Record
    • GetReferencedName(lref) is either "eval" or "arguments"
  7. Call PutValue(lref, r)

Thus, var i = 0; i += ++i is:

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.

Completely according to spec.

However, in C++, this is specifically defined to be undefined behaviour, thus on a different compiler you might also get 1. Or 99. Or it could set your computer on fire. All of those would be standard-compliant compilers. Thus, most people will recommend you only use pre/post-incremented variable once in a statement.




回答2:


I believe this is because javascript see's var i = 0; i += ++i; as this:

var i = 0;
++i = 1;
i += 1;

It's because the ++i turns i into 1 before performing +=, so it's 0 + 1 = 1

In fact, the more I think about it, why would it do anything else?

There are two assignments taking place, and one has to be done before the other. So the two options would be either:

  • do ++i first, and make it i = i + 1 where i starts at 0 and equates to 1

or

  • do the += first, and make it i = 0 + (++i) which would also equate to 1


来源:https://stackoverflow.com/questions/23930661/pre-increment-in-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!