I've just been watching a tutorial which talked about the following if statement:
var a = 0;
if(a || a === 0){...};
It states that operator precedence means that a === 0 is evaluated first, as it has a higher precedence than ||.
I've no real issue with that, but the tutorial goes on to say that 'a' is then evaluated - but surely it's short-circuited?
I know it should be pretty simple, but I'm new to JS. Is this a mistake or am I misunderstanding what's being said?
You can test this easily enough with a getter. If a is true, the getter is called once, meaning that obj.a === 0 is never evaluted due to short-circuiting:
let obj = {
get a() {
console.log("getting a")
return true
}
}
if(obj.a || obj.a === 0){
console.log("true")
};
If a is falsey as is the case when a id 0 , both side are evaluated:
let obj = {
get a() {
console.log("getting a")
return 0
}
}
if(obj.a || obj.a === 0){
console.log("true")
};
No, the equivalence doesn't happen first:
var a = 0;
if(a || a === 0){...}
The a in this case is falsey and so the || continues onto the next statement, equivalent to:
if(a === 0){...}
At this point, the equivalence takes place and is clearly true, no short circuiting takes place because the expression is evaluated left to right.
The reason for this is that either side of the OR is a different expression and the expressions are evaluated from left to right.
expr1 || expr2
Once expr1 has been evaluated, if it is truthy only then does short-circuiting take place and the expression as a whole be truthy. If this isn't the case expr2 will be evaluated and if that is truthy then the expression as a whole will be truthy, otherwise it will be falsey.
Related
I understand how short-circuit evaluation works when using the logical or operator in JavaScript, but I've run into what seems to be a weird edge case I don't fully understand.
So, this snippet works the way I would expect:
const a = 'a' || 'b';
with a having a value of 'a'.
And of course, this also works the way I would expect:
const a = false || 'b';
with a having a value of 'b'.
However, I've run into this weird situation with an expression like this:
const a = true || true || true ? 'a' : 'b';
where a now has a value of 'a'. I've tried other combinations, such as:
const a = true || false || true ? 'a' : 'b';
and a still has a value of 'a'.
Another thing to try is something like this:
const fn = () => true ? 'a' : 'b';
const a = true || fn();
and of course a has a value of true, and fn is never called.
What's going on here?
A logical OR || is evaluated from left to right and the first value that evaluates to a truthy value is returned, or the last one if none of them evaluates to true.
In this case, the first true trivially evaluates to true, thus the whole condition returns true:
true || true || false
As a result, the first expression of the ternary operator is evaluated, in this case 'a':
const a = true || true || true ? 'a' : 'b';
For this reason, a equals 'a'.
The same logic applies to the other cases you listed.
Sorry, I'm a bit of a noob when it comes to javascript. But here is my problem:
The following function returns -1 when 0 is inputed
function foo(bar){
return bar || -1;
}
foo(0);
is there a nice and elegant way to allow the || operator to read 0 (specifically 0, not all falsy values) as a valid value so that the function retuns 0? Or do I have to do this:
function foo(bar){
if(bar === 0){
return 0;
} else {
return bar || -1;
}
}
foo(0);
Edit:
Thank you everyone for your answers!
For those wondering, the question was asked to find the solution to the same issue with optional parameters. The following code is an example of how it could be applied.
function Point(x,y,meta){ //meta is an optional parameter. In this case I wanted to set meta to 0, but it was being set to null.
this.x = x;
this.y = y;
//this.meta = meta || null; This line is the old code that would set meta to null when 0 is inputed.
this.meta = meta === 0 ? 0 : (meta || null); //the fix suggested by many users is applied here.
};
var foo = new Point(1,2,0);
console.log(foo.meta); //foo.meta is now 0 instead of null!
That's the way JavaScript works. All values are either truthy or falsy. Zero happens to be a falsy value. You can simplify your function with a ternary though.
function foo(bar) {
return bar === 0 ? 0 : (bar || -1);
}
The tightest you can get is to collapse your if-else in to a single return, a la:
return bar === 0 ? bar : (bar || -1);
Because || compares truthy/falsy values, you have to explicitly handle (using strong typing) the 0 case.
It's hard to tell from your question, but usually when I'm overriding the truthy/falsy nature of comparisons, it's to default a value. In that case, it's to detect if my function has been given an undefined value, and to use some sane default in its place.
You could rewrite foo like this using the ternary operator:
function foo(bar) {
return bar === 0 ? 0 : (bar || -1)
}
The syntax for the ternary operator is condition ? expr1 : expr2. If condition is truthy, it will return expr1, otherwise it will return expr2.
Here's more information on the ternary operator
The other approach is to look at the number of arguments received and set default value that way.
function foo(bar){
if (arguments.length === 0) {
return -1;
}
return bar;
}
function foo(bar){
return typeof bar === "undefined" || bar === null ? -1 : bar;
}
foo(0); // should give 0
foo(false); // should give false
var a; // undefined variable
foo(a); // should give -1
foo(null); // should give -1
var b = {}; // object
foo(b.a); // should give -1 (undefined property)
Well, the intention of this if is to check for missing (non-present) value. In JavaScript the value is missing if it is:
undefined
null
The best way to check something for undefined is to strictly (===) check its type for equality to "undefined" string - this way you don't get an exception if bar can't be evaluated.
But, if your expression is not undefined, you can then safely check its' value with comparison bar===null.
Thus, we have both cases covered and we are not getting exceptions.
I was reading the javascipt code in some application and code was this
getTotalFees:function(){
return this.grid
&&this.grid.getStore().sum('fees');
}
Now i am confused what it will return.
IT looks to me like
return a&&b
won't it return true or false rather than b
Logical AND (&&):
expr1 && expr2 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.
Source
So, basically:
If the first parameter is falsy, it returns that parameter. Else, it literally returns the second parameter.
In your case, this means that, if this.grid exists, it returns this.grid.getStore().sum('fees');
This is done to protect against calling a method on undefined property, witch would cause an error. So if this.grid is undefined, then undefined is returned.
In expressions if a && b when a equals to false (or in javascript it can be an expression like in Cerburs answer), then a is returned.
Similarly with || operator, the first from the left that equals to true (in javascript not 0, not undefined, not null, not NaN, and not false of course) is returned.
You misunderstand what && does. Let a and b be "entities". Then a && b does:
evaluate a
if a is falsy return a
if a is truthy evaluate b
return b
Example:
var f = function() {
console.log("test");
return 'foo';
}
> 0 && f()
0
> 1 && f()
test
"foo"
Note that in first case we didn't get console.log because f() was not evaluated because 0 is falsy. This property is important and actually
a && b != b && a
even though mathematically it should be the same (but it is not due to side-effects of evaluation).
Falsy values include: 0, false, "" (empty string), null, undefined,NaN (not a number type). I don't think there are any other possible values (someone correct me if I'm wrong). Every other object is truthy.
So in your case the code can be rewritten as:
if (this.grid) {
return this.grid.getStore().sum('fees');
} else {
return this.grid;
}
Ok, let's assume that this.grid.getStore().sum('fees') returns something, let's say "okay!".
now the return statement in your code is a convoluted way of saying :
if(this.grid)//this.grid is defined and doesn't evaluate as 'false'
return this.grid.getStore().sum('fees');
else
return this.grid;
if this hasn't got a grid, we return undefined, else we call gridStore... and return its own return.
It is a common way of avoiding "undefined has no method 'gridStore'"
the VERY important part is that, in a && f(), f() will NOT be called if 'a' evaluates to false. there are many things that evaluate to false, such as any undefined variable, null, empty strings... (note that strings that contain falsy things like "false" or "0000" are actually truthy). or even unreadable babble like function(){return null;}(); may evaluate as false.
Why does the following code produce a == 3?
var x = "abc";
var y = 3;
var z = "xyz";
var a = x && y || z;
http://jsfiddle.net/thinkingmedia/qBZAL/
I would have expected this to result in a == true.
Why is the logical operator evaluating "abc" as true but doesn't evaluate 3 as true. Instead it produces 3 as the result.
Furthermore, if you change y = 0 then a == "xyz" which means that && treated 0 as false. What happen to treating a number as a number?
What's going on here with the logical operators?
This is to be expected.
In JavaScript (and many other languages), not only Booleans themselves are true or false, but other objects can be truthy or falsey as well (See the docs on mdn):
The value […] is converted to a boolean value, if necessary. If value is […] is 0, -0, null, false, NaN, undefined, or the empty string (""), [it is] false. All other values, including any object or the string "false", create […] true.
The logical operators || and && don't return true or false, rather they return the last argument to influence whether they are truthy or falsey (reference):
expr1 && expr2 – 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.
expr1 || expr2 – Returns expr1 if it can be converted to true; otherwise, returns expr2. Thus, when used with Boolean values, || returns true if either operand is true; if both are false, returns false.
The first step is to evaluate "abc" && 3.
false && 3 would return false,
true && 3 would return 3.
"abc" is not false, so JavaScript takes the second part, i.e. 3.
The second step is to evaluate 3 || "xyz". Here, JavaScript takes the first value which is not null, i.e. 3. This is similar to this.firstObject ?? this.defaultValue in C#: the second part is taken only when the first part is null.
the side effect is that you can do things like this:
x = x || {};
to set a variable to a default if it is not set.
Or
TrackingManager && TrackingManager.track("user was here")
to avoid bulkier if statements.
var c = false;
if(c=[] && c.length==0)alert('hi');
hi is not alerted because c is still false when it executes the second operand of &&, can someone explain how the boolean operands in if condition are executed and in what order?
I believe this is just a precedence issue - && is binding tighter than =. Your code is equivalent to:
if (c = ([] && c.length == 0))
{
alert('hi');
}
So it's assigning c the value false rather than the empty array.
Try this instead:
if ((c = []) && c.length == 0)
{
alert('hi');
}
EDIT: To address Tryptich's comment - I did try this before posting :) As CMS said, an empty array is considered true. Try this:
if (c = [])
{
alert('empty array is true');
}
or even just this:
if ([])
{
alert('empty array is true');
}
I checked the spec before posting - I was somewhat surprised that an empty array is considered true, but it is...