Search code examples
javascriptincrementoperator-precedence

Javascript increment operation order of evaluation


I know the what the postfix/prefix increment/decrement operators do. And in javascript, this seems to be no different.

While I can guess the outcome of this line easily:

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

as ++ operators appear within separate expressions.

It gets a bit complicated as these operators appears within the same expression:

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?

and my question is, how does Javascript (V8 in this case, as I tested these in Chrome) end up evaluating the addition expression in 2nd and 3rd example differently?

Why does foo end up evaluating differently than foo++. Isn't postfix ++ supposed to increment after the expression and just evaluate to foo within expression?


Solution

  • Just look at:

    foo++ + ++foo
    

    Mentally rewrite it to:

    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
    

    And 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
    

    So everything is evaluated left to right, including the incrementation.

    The crucial rule to understand is that in JavaScript the whole left hand side (LHS) is executed, and the value memorized, before any operation gets done on the right hand side (RHS).

    You can either confirm the evaluation order by reading the standard or just place a runtime error in your expression and look what happens:

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