Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pre increment in Javascript

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?

like image 430
nhaa123 Avatar asked May 29 '14 10:05

nhaa123


People also ask

What is the difference between i ++ and ++ i in JavaScript?

++i returns the value of i after it has been incremented. i++ returns the value of i before incrementing. When the ++ comes before its operand it is called the "pre-increment" operator, and when it comes after it is called the "post-increment" operator.

What does 1 ++ mean in JavaScript?

The increment operator ( ++ ) increments (adds one to) its operand and returns the value before or after the increment, depending on where the operator is placed.

Can I do ++ in JavaScript?

JavaScript has an even more succinct syntax to increment a number by 1. The increment operator ( ++ ) increments its operand by 1 ; that is, it adds 1 to the existing value.

What is the difference between ++ and += in JavaScript?

++ increases the integer by one and += increases the integer by the number of your choice.


1 Answers

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.

like image 65
Amadan Avatar answered Oct 11 '22 09:10

Amadan