Does a javascript if statement with multiple conditions test all of them? - javascript

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?

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.

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.

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.

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

It will only test all the conditions if the first ones are true, test it for yourself:
javascript: alert (false && alert("A") && false);

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

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.

It exits after seeing that b does not equal one.

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)

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.

Related

Eloquent Javascript Chapter 5 Exercise Question, using !array.some

This one stumped me for a while, and I eventually just looked at the solution online. The hint was fairly cryptic, and manipulating "De Morgan's Laws" in JS with &&, !, || is pretty complicating still. I'm starting to grasp it, but not quite there yet. I imagine I will need a fair bit of practice and time to understand these concepts thoroughly. Anyway, here is the question for one of the exercises at the end of chapter 5:
Analogous to the some method, arrays also have an every method. This one returns true when the given function returns true for every element in the array. In a way, some is a version of the || operator that acts on arrays, and every is like the && operator.
Implement every as a function that takes an array and a predicate function as parameters. Write two versions, one using a loop and one using the some method.
function every(array, test) {
// Your code here.
}
console.log(every([1, 3, 5], n => n < 10));
// → true
console.log(every([2, 4, 16], n => n < 10));
// → false
console.log(every([], n => n < 10));
// → true
I was able to get the first version using array.every; it wasn't too hard. But the solution for using the some method I still don't understand. Here's the solution to the second part of the question:
function every(array, test) {
return !array.some(element => !test(element));
}
I'm trying to work this out in my head, and thought that maybe a SO member could help me understand what's happening. Can someone talk me through this?
Thanks in advance!
Jordan
You could build a table of truth and have a look which value yields which result.
This example take the second example and shows for the first two elements an intermediate result, pretending here would stop the loop and the final result.
n < 10 !(n < 10)
value compare1 every compare2 some !some comment
--------- --------- --------- --------- --------- --------- -------------------
2 true false
4 true false
true false true intermediate result
16 false true
false true false final result
^^^^^ ^^^^^
By mentioning De Morgan's laws, a term can be expressed by changing the operator from logical AND && to logical OR || or vice versa by taking negated values and finally negate the whole expression.
a && b && c
!(!a || !b || !c)
Both expressions are equal (for boolean values).
Array#every acts like using && and Array#some like ||.
To negate some, take every and vice versa. This replacement need to negate the condition inside of the callback and a negation of the the result.

Compare and assign numbers

This procedure has likely been covered on SO in some form but I do not know how to find it.
I would like to compare one value with two others and assign a variable ideally in the same step.
In my case, I have a user Id (A) and two sample user ids ( B and C )
Either B or C in this situation must be equal to A.
I want to check if A == B or A == C and then set a variable (other) to the B or C id that DOES NOT equal A.
I know I could do
if (A == B) {
var other = C;
return other
}
else {
var other = B
return other
}
Simple enough but does anyone know of a more efficient way? Any JS libraries are allowed.
You can do that with a ternary condition:
var other = A == B ? C : B;
In this case, if A and B are the same, other will be set to C, otherwise it'll be set to B.
Simple enough but does anyone know of a more efficient way?
You can use the if condition what you are using presently or you can use the ternary operator. Both are having the same performance. Its just the matter of readability to what you want to use. As far as performance is concerned both the ways are almost equally efficient.
Just saw this JSPerf test and found that if condition is faster than ternary condition.

a && b && c VS if - What's the difference on performance?

Just saw a line of code: a && b && c. I think this should be equivalent to if(a && b) {c}. But I'm really curious that is there any performance difference on these code, or it's just simply cool to put it in one line?
This is actual code: sourcesPanel && sourcesPanel.tips && sourcesPanel.tips.clearTimers()
The sourcesPanel and sourcesPanel.tips are two objects in the program.
Basically, I think it's checking if those two objects exist, it they exist, call that clearTimers function.
The logical operators in JS have a very important behavior: they return the first conclusively failing or succeeding operand. If does not.
The behavior of if (a) { if (b) { ... is pretty simple: if they are truthy, enter the block.
The behavior of && is different:
foo = 1 && 2 && 3; // foo = 3, succeeds all the way through
foo = 1 && 0 && 3; // foo = 0, failed at 0
foo = 1 && null && 3; // foo = null, failed at null
When the logical operators are used within an if, the behavior appears to be exactly the same. Used on their own or with an assignment, they behave in a relatively unexpected way.
Take the use of || to provide defaults:
opt = opt || {foo: bar};
If opt was truthy (for an object, present) use it, otherwise use the defaults. The other logical operators behave the same way.
That is actually a double check and not a simple conditional check like you sugest: if(a && b) {c}.
The equivalent to a && b && c would be:
if (a && b){
if(c){
// do something
So all a, b and c have to be truthy.
a && b && c is mostly more practical than doing
if (a){
if (b){
if(c){
// do something
But in a triple check like a && b && c b will never be evaluated if a evaluates false. Thus sparing time. The same for c that will only be evaluated if a and b also were true.
There is a performance improvement in some circumstances.
The line is executed step by step from left to right, and leaves as soon as it fails.
So, if a is false, b and c will not be evaluated.
You see this a lot in bash where one instruction is dependent upon another succeeding, but the first has to be attempted no matter what.

meaning of the AND operator in this line

What is the meaning of && in this JavaScript code?
function doIt(a) {
var b = a.parents(),
c = 1;
return b.each(function() {
jQuery(this).hasClass("free-content") && (c = 0)
}), c
}
normally I would think this would be a logical operator AND, but I can't figure out what it does in this line.
The logical AND operator in this case is used in place of an IF-statement. It will set c to 0 if jQuery(this).hasClass("free-content") returns a truthy value.
It's equivalent to:
if (jQuery(this).hasClass("free-content")) {
c = 0;
}
You wondering what it means is actually the reason I dislike this type of coding and consider it a bad practice. It's hard to read and can create confusion, which in turn can create bugs.
It's also worth noting what logical AND returns, if you want to use the returned value:
(Logical AND) Returns expr1 if it can be converted to false; otherwise, returns expr2. Thus, when used with Boolean values, && returns true if both operands are true; otherwise, returns false.
Here's an example showing, in my opinion, bad code since it's hard to follow:
var foo = bar && baz || qux;
The above code is equivalent to:
var foo;
if (bar && baz) {
foo = baz;
} else {
foo = qux;
}
Summary: Do not use logical operators as a nifty way to replace IF-statements or to save keystrokes. It will most likely come back and bite you or someone else in the ass.
I know there will be people arguing against me on this (usually the same people who doesn't want to use semicolon because ASI), but it's just a really bad idea to write code that only an expert would understand. There's no argument against it.
return b.each(function () {
jQuery(this).hasClass("free-content") && (c = 0)
}), c
b.each loops over all entries in b, and checks whether the current element has the class free-content set. Only if that yields true, the second part of the expression is evaluated – because they are concatenated via &&, and JavaScript stops evaluating such an expression when the first part is false, because then the whole expression can’t become true any more.
So if there is an element with that class, the second part is evaluated – and thereby c is set to the value 0 (because that’s the assignment operator = there, and not a comparison).
And after that each loop is finished, the value of c is returned to the outside – because each() and c are connected via the comma operator , here, which evaluates its operands from left to right and then “returns” the second one.
JavaScript allows a lot of “fancy” coding like this, but as Marcus already said in his answer, that is hard to read, and there is no actual advantage here over, say
b.each(function() {
if(jQuery(this).hasClass("free-content")) {
c = 0;
return false;
}
});
return c;
I added the return false here inside the each loop, because once we found an element with that class, we don’t need to search the rest of them any more – that’s something that the person who came up with the original code forgot to do in all their “fancy-ness” … their loop will continue to iterate over all of b’s elements, not matter if it finds the element it is looking for in the first round already.

3 ways to say if:else, but which one?

In an interesting blog post, I read that there are three ways to write an if:else statement:
//method 1 - regular
if(boolean) {true condition} else {false condition}
//method 2 - shorthand
boolean ? (true condition) : (false condition)
//method 3 - logical operators
boolean && (true condition) || (false condition)
//eg: var c = r==0 && "small" || "big";
EDIT: third method IS an if:else statement, when the first part of it becomes true, the whole statement turns to true||(false condition). all modern compilers ignore the false condition then.
Now I have two questions here:
Which one of them is the most optimized? (from performance view, if any of them differs from the other, please explain why)
Is there any more methods to write an if:else statement?
Don't worry about the performance of these statements unless you are planning on running them a few thousand times per second.
If you are going to run them that often, test it yourself, you'll probably find different results under different browsers.

Categories