Search code examples
javascriptoperator-precedence

POSTFIX and PREFIX increment/decrement precedence in JavaScript


I've been coding for years and suddenly stuck to some simple thing about operators precedence in case of increment/decrement operators.

According to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence the postfix increment/decrement has higher priority than the prefix one. So, I expect that in expression

x = --a  + a++;  

the increment will be calculated first and only after that the decrement. But, in tests this expression calculates left-to-right like that operators have the same priority. And as result a=1;x = --a + a++ equals to 0 instead of 2.

Ok. Assuming that prefix/postfix operators have the same precedence, I try to reorder it with parentheses:

a=1;x = --a  + ( a++ )

But again, the result will be 0 and not 2 as I expected.

Can someone explain that please? why parentheses here do not affect anything? How can I see that postfix has higher precedence than prefix?


Solution

  • Operator precedence is not the same thing as evaluation order.

    Operator precedence tells you that

    f() + g() * h()
    

    is parsed as

    f() + (g() * h())
    

    (because * has higher precedence than +), but not which function is called first. That is controlled by evaluation order, which in JavaScript is always left-to-right.

    Parentheses only override precedence (i.e. they affect how subexpressions are grouped), not order of evaluation:

    (f() + g()) * h()
    

    performs addition before multiplication, but in all cases f is called first and h last.

    In your example

    --a + a++
    

    the relative precedence of prefix -- and postfix ++ doesn't matter because they're not attached to the same operand. Infix + has much lower precedence, so this expression parses as

    (--a) + (a++)
    

    As always, JS expressions are evaluated from left to right, so --a is done first.

    If you had written

    --a++
    

    that would have been parsed as

    --(a++)
    

    (and not (--a)++) because postfix ++ has higher precedence, but the difference doesn't matter here because either version is an error: You can't increment/decrement the result of another increment/decrement operation.

    However, in the operator precedence table you can see that all prefix operators have the same precedence, so we can show an alternative:

    // ! has the same precedence as prefix ++
    !a++
    

    is valid code because it parses as !(a++) due to postfix ++ having higher precedence than !. If it didn't, it would be interpreted as (!a)++, which is an error.