I am an experienced developer, but I just ran into an issue that took me a while to figure out and am looking for an explanation. I was relying on short circuiting and spent more time than I care to admit debugging this. If this belongs on another Stack Exchange site, please advise.
I expect the following to evaluate to false, but it passes:
(false && true || true) => true
It is as though it's being interpreted as this:
((false && true) || true) => true
... but the solution is this:
(false && (true || true)) => false
Why doesn't false short circuit the operation in the first example? Is there some sort of lookahead I don't know about?
Solution summary: For those who (like me) never knew conditional operators have a similar precedence as mathematical operators - the same concept of implied parenthesis applies:
3 * 2 + 1 => (3 * 2) + 1 => 7
false && true || true => (false && true) || true => true
Logical AND (
&&) has a higher precedence than logical OR (||).You could fix the problem by adding the parentheses you used in your example.
However, it would be much more readable to use an explicit
ifstatement instead:Here's a reference chart for operator precedence in JS. (See #13 and #14.)
If you're having a hard time understanding precedence, try substituting
*for&&and+for||:Clearly, by order of operations, the
x * ywill be executed first. So if you want to execute they + zfirst instead, you would use parentheses.Short circuiting has nothing to do with the syntax. It's simply a quirk of boolean operators. So don't think of it like
The short circuiting doesn't call some sort of "abort" function that exits the entire operation. It's simply that the boolean operators will ignore their second argument (
bina && b) if it's already ascertainable what the final result will be. (For example,false && (anything)is always false, so&&is lazy and doesn't bother evaluating the second argument.)Okay, so applying the precedence rules, we get:
Therefore, the
&&is evaluated first. Since it's lazy, it sees thefalseand immediately returnsfalse:Now it's
||'s turn to evaluate. It sees thefalsethat&&just returned, and it can't short-circuit becausefalse || truecould still be true. So it has to evaluate thesomethingelseto get the final result.Therefore, the code
if((false && anything) || somethingelse)is essentially equivalent toif (somethingelse).