121

In javascript, when using an if statement with multiple conditions to test for, does javascript test them all regardless, or will it bail before testing them all if it's already false?

For example:

 a = 1
 b = 2
 c = 1

 if (a==1 && b==1 && c==1)

Will javascript test for all 3 of those conditions or, after seeing that b does not equal 1, and is therefore false, will it exit the statement?

I ask from a performance standpoint. If, for instance, I'm testing 3 complex jQuery selectors I'd rather not have jQuery traverse the DOM 3 times if it's obvious via the first one that it's going to return FALSE. (In which case it'd make more sense to nest 3 if statements).

ADDENDUM: More of a curiosity, what is the proper term for this? I notice that many of you use the term 'short circuit'. Also, do some languages do this and others dont?

Keez
  • 65
  • 1
  • 13
DA.
  • 39,848
  • 49
  • 150
  • 213
  • @Josh: I completely appreciate the idea that this is micro-optimization. Which is good to know. That said if one option is more optimized than another, I assume it's good to know and get in the habit of using said method. (Plus, well, I was just really curious as to the answer as well) – DA. Dec 18 '09 at 20:34
  • 22
    Strictly speaking, this isn't a premature optimisation. In languages with short-circuit logic, it's important to know under what conditions some methods won't be executed; if you're relying on their side effects, for example. – Rob Dec 18 '09 at 20:35
  • 5
    Here's another question about "short circuit evaluation": http://stackoverflow.com/questions/1232603/do-all-programming-languages-have-boolean-short-circuit-evaluation – David Dec 18 '09 at 20:37

10 Answers10

172

The && operator "short-circuits" - that is, if the left condition is false, it doesn't bother evaluating the right one.

Similarly, the || operator short-circuits if the left condition is true.

EDIT: Though, you shouldn't worry about performance until you've benchmarked and determined that it's a problem. Premature micro-optimization is the bane of maintainability.

Anon.
  • 58,739
  • 8
  • 81
  • 86
  • 1
    Excellent answer (both the technical part and the management issue). thanks! – DA. Dec 18 '09 at 20:30
  • 5
    If you DO ever want it to execute all parts of the boolean statment you could use & and | for and and or repspectively – Zoidberg Dec 18 '09 at 20:32
  • 27
    This condition isn't necessarily always about performance. Sometimes you might be doing a null check and say if your null check is condition a and then you try to do a (b == value + 1) for your second check you will get an error if all three conditions if conditions were checked. – infocyde Dec 18 '09 at 21:08
  • 4
    Indeed, short-circuiting isn't about performance. The original question, however, was asking from a performance standpoint. – Anon. Dec 18 '09 at 21:11
  • 1
    very good. Doing this kind of micro optimization (among others) can have a big impact inside a scroll event loop, lets say for parallax calculation of multiple elements for instance or even sticky bar. take this ex: `if (!barSticky && bar.parent().offset().top <= document.documentElement.scrollTop)` the second condition is a more costy calculation, the first one is just a boolean. :) – antoni Oct 08 '16 at 18:48
  • any info where I can get more principle like that EDIT: ? – buncis May 15 '18 at 05:30
  • This isn't necessarily just about performance. Consider the following conditional statement preceding an instruction to close the page "if(PageIsDirty() || confirm('Are you sure you want to discard your changes and close the page?'))". In this case, you need to know the second condition is not going to be tested if the first true. – Jimbo Aug 28 '18 at 09:02
  • Correction: if(!PageIsDirty() || confirm('Are you sure you want to discard your changes and close the page?')) – Jimbo Aug 28 '18 at 09:08
15

From a performance standpoint, this is not a micro-optimization.

If we have 3 Boolean variables, a, b, c that is a micro-optimization.

If we call 3 functions that return Boolean variables, each function may take a long time, and not only is it important to know this short circuits, but in what order. For example:

if (takesSeconds() && takesMinutes())

is much better than

if (takesMinutes() && takesSeconds())

if both are equally likely to return false.

Gust van de Wal
  • 5,211
  • 1
  • 24
  • 48
Brad
  • 1,360
  • 4
  • 18
  • 27
14

That's why you can do in javascript code like

var x = x || 2;

Which would mean that if x is undefined or otherwise 'false' then the default value is 2.

Jason Towne
  • 8,014
  • 5
  • 54
  • 69
azazul
  • 1,205
  • 1
  • 7
  • 5
10

In case someone's wondering if there is a way to force the evaluation of all condition, in some cases the bitwise operators & and | can be used

var testOr = true | alert(""); //alert pops up
var testAnd = false & alert(""); //alert pops up

These should be used really carefully because bitwise operators are arithmetic operators that works on single bits of their operand and can't always function as "non short-circuit" version of && and ||

Example:

-2147483648 && 1 = 1 

but

-2147483648 & 1 = 0

Hope it helps someone who arrived here looking for information like this (like me) and thanks to @Max for the correction and the counter-example

ivcandela
  • 331
  • 3
  • 12
  • 1
    This answer is wrong. & and | are bitwise operator, they are NOT 'non short-circuit versions of && and ||'. Bitwise operators are arithmetic operators that works on single bits of their operand. Example: -2147483648 && 1 = 1 but -2147483648 & 1 = 0. More info here: https://en.wikipedia.org/wiki/Bitwise_operation – Max Aug 22 '17 at 15:28
  • 1
    @Max actually i didn't know this, i've been using this (what i now call "trick") since i was studying C. Luckily such inputs that would've break my code never came up. I corrected my answer, I owe you – ivcandela Sep 25 '17 at 22:28
  • @DJDaveMark sorry i could not get your `false && (alert(""))` solution to work :/ – ivcandela Mar 02 '18 at 15:30
  • @ivcandela Neither could I. If I wasn't on my phone I would have tested it 1st ;o) Pity you can't edit comments. I just deleted it and added another below – DJDaveMark Mar 03 '18 at 18:16
  • The simpler and better way to force evaluation is to save the results in variables then test against the variables i.e.: `var a=false; var b=check(); alert(a && b);` – DJDaveMark Mar 03 '18 at 18:17
7

It will only test all the conditions if the first ones are true, test it for yourself:

javascript: alert (false && alert("A") && false);
albertein
  • 26,396
  • 5
  • 54
  • 57
3

Another reason why stopping evaluation with 1 or more parameters to the left.

if (response.authResponse && (response.authResponse.accessToken != user.accessToken)){ ... }

the second evaluation relies on the first being true and won't throw a compile error if response.authResponse is null or undefined etc because the first condition failed.

Other languages had this problem in the early days and I think it's a standard approach in building compilers now.

PazoozaTest Pazman
  • 749
  • 12
  • 33
3

It short circuits - only a and b will be compared in your example.

David M
  • 71,481
  • 13
  • 158
  • 186
2

It exits after seeing that b does not equal one.

Annie
  • 6,621
  • 22
  • 27
2

For anyone on this question confused because they're not seeing the short-circuit behaviour when using an || in conjunction with an ? operator like so:

x = 1 || true ? 2 : 3 // value of x will be 2, rather than 1 as expected

it seems like the short circuit rule isn't working. Why is it evaluating the second term of the || (true ? 2 : 3) when the first is true? It turns out to be an order of operations problem because the above is the equivalent of

x = (1 || true) ? 2 : 3

with the || evaluated first and the ? evaluated second. What you likely want is:

x = 1 || (true ? 2 : 3)

BrightEyed
  • 366
  • 2
  • 10
2

For this case:

a = 1
b = 2
c = 1

if (a==1 && b==1 && c==1)

You can use:

if ([a, b, c].every(x => x == 1))
    // do something if a, b and c are equal to 1.

If you want to know if at least one is equal to 1, use the some() method instead of every():

if ([a, b, c].some(x => x == 1))
    // do something if a, b or c is equal to 1.

every() and some() are array methods.