70

So, I'm looking into writing a slightly more complex operation with logic operators in an if-else statement. I know I can do parentheses, and I know it's the better way of doing this, but I've gotten curious and so I'm going to ask. If I were to do something like this:

if (firstRun == true || selectedCategory != undefined && selectedState != undefined) {
//Do something
} else {
//Do something else
}

How will that be operated without the use of parentheses? I know there is an order of operations for logic operators, similar to PEMDAS, right? I'm curious if it'll be ran something like this:

firstRun == true || (selectedCategory != undefined && selectedState != undefined)

or maybe if the 'OR' operator takes precedence instead and it ends up going like:

(firstRun == true || selectedCategory != undefined) && selectedState != undefined

The full list would be nice, if you can find it somewhere, of the order of operations for this. Thanks!

Jtaylorapps
  • 5,680
  • 8
  • 40
  • 56

6 Answers6

92

My rule of thumb, which covers basically 99% of all use cases for conditional statements, is:

  1. Grouping: ()
  2. Member access . or [...]
  3. Not: !
  4. Comparison, e.g. < , >= , === , !=, ...
  5. Logical AND &&
  6. Logical OR ||

MDN gives you the exhaustive breakdown: JavaScript Operator Precedence

So for your example:

(firstRun == true || selectedCategory != undefined && selectedState != undefined)

equals

(firstRun == true) || ((selectedCategory != undefined) && (selectedState != undefined))

For anything more complex than the above mentioned cases, I would look into refactoring the code for readability's sake anyway!

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Christoph
  • 50,121
  • 21
  • 99
  • 128
  • What about `new`? It has the same precedence as member access and function calls, so I assume that means left-to-right? `new Foo().bar()` is equivalent to `(new Foo()).bar()`? And `new Foo()(3)` is equivalent to `(new Foo())(3)`? – chharvey Aug 13 '16 at 18:06
  • 5
    @chharvey No. `new` actually runs with a lower precedence than `.` (the dot operator) which means `new Foo().bar() === new (Foo().bar())`. This is painfully obvious when attempting to format the current time with `new Date.toLocaleString()` which throws an error. Instead, one must use `(new Date).toLocaleString()` or something completely different like `Date.now()`. – Frozenfrank Oct 27 '18 at 07:15
  • Rember to account for "short-circuiting" where (a || (b * c)); will evaluate `a` first, then produce `a` if `a` is "truthy". It does this regardless if the right side has higher precedence. As explained in the MDN docs you posted above. – JD Tripp Jul 01 '23 at 00:07
37

There is a pretty good rule of thumb to this. Think of these operators as of mathematical ones:

  • AND is multiplication (eg. 0 * 1 = 0 => FALSE)
  • OR is adding (eg. 0 + 1 = 1 => TRUE)

When you remember this, all you have to know is that multiplication always comes before addition.

Michal Leszczyk
  • 1,849
  • 15
  • 19
11

See this chart for precedence.

I'm not going to explain what happens because the next guy reading your code will think: "WTF? Does that do what it should?"

So the better solution is to wrap the terms in parentheses even if you know the precedence, applied it correctly and the code works

This follows the old wisdom that you shouldn't do everything you can just because you can do it. Always keep an eye on the consequences.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Yeah, I understand what you're saying and I'm aware, the point of asking for me was more for personal knowledge than anything. Thanks – Jtaylorapps Jun 22 '12 at 14:15
3

See Operator precedence.

&& is before ||, so your expression is equivalent to:

firstRun == true || (selectedCategory != undefined && selectedState != undefined)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Blindy
  • 65,249
  • 10
  • 91
  • 131
0

It will be the first:

firstRun == true || (selectedCategory != undefined && selectedState != undefined)

As a general rule, in most programming languages, AND has higher precedence.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mariy
  • 5,746
  • 4
  • 40
  • 57
0

While logical operator precedence is not actually defined in the ECMAScript Specification, MDN does a pretty good job of it and even has a separate page for logical operators.

My concern I suppose, since logical operator precedence is not actually defined in the ECMAScript specification, each individual browser vendor can potentially be different (I'm talking to you, Internet Explorer!), so your mileage may vary.

In the event anyone wants to test this across different browsers, here's a test case fiddle: http://jsfiddle.net/HdzXq/

$(document).ready(function() {
    function log(test) {
        $('div#out').append($('<p />').text(test));
    }

    function testOperatorPrecedence() {
        log('(false || false && false) === ' + (false || false && false).toString());
        log('(false || false && true) === ' + (false || false && true).toString());
        log('(false || true && false) === ' + (false || true && false).toString());
        log('(false || true && true) === ' + (false || true && true).toString());
        log('(true || false && false) === ' + (true || false && false).toString());
        log('(true || false && true) === ' + (true || false && true).toString());
        log('(true || true && false) === ' + (true || true && false).toString());
        log('(true || true && true) === ' + (true || true && true).toString());
        log('----------------------------');
        log('(false || (false && false)) === ' + (false || (false && false)).toString());
        log('(false || (false && true )) === ' + (false || (false && true)).toString());
        log('(false || (true && false)) === ' + (false || (true && false)).toString());
        log('(false || (true && true )) === ' + (false || (true && true)).toString());
        log('(true || (false && false)) === ' + (true || (false && false)).toString());
        log('(true || (false && true )) === ' + (true || (false && true)).toString());
        log('(true || (true && false)) === ' + (true || (true && false)).toString());
        log('(true || (true && true )) === ' + (true || (true && true)).toString());
    }
    testOperatorPrecedence();
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
pete
  • 24,141
  • 4
  • 37
  • 51