A logical statement always returns a boolean value, true or false.
But how do you retrieve the true statement in a OR logical operation?
In JavaScript, the OR and AND operators always return one of their operands. The OR operator returns the first falsy operand (and doesn't evaluate any operands after that) or the last operand if they are all truthy. The AND operator similarly returns the first truthy operand or the last operand if they are all falsy.
If you wish the result to be a boolean, you can use the ! operator which returns true for falsy values and false for truthy values.
To sum it up:
!!(a || b) will return true if a and/or b are truthy and false otherwise.
a || b will return a if a is truthy and b otherwise.
EDIT:
After some explanations it seems that what you are looking for is separating the evaluation of the OR.
if (a === 56) {
// a is what you are looking for
} else if (b === 56) {
// b is what you are looking for
} else {
// neither a nor b are what you are looking for
}
The above piece of code does the exact same evaluations as your code but you have a branch of code that executes when the first expression is true and another branch which executes if the first expression is false and the second expression is true.
Related
I have an OR expression that should return the operand that is anything else than NaN:
(1 || NaN) // evaluates to 1
(NaN || 1) // evaluates to 1
But when the other operand is also a falsy value like 0, null, undefined or false, Javascript returns always the rightmost operand:
(0 || NaN) // evaluates to NaN
(NaN || 0) // evaluates to 0
// same for combinations of 0, null, undefined and false
Is there a way to fit the desired behaviour "Return the operand that is not NaN" into a nice & short expression or do I have to rely on an if/else construct?
You could add a default falsy value at the end of the expression, like
result = yourValue0 || yourValue1 || 0;
In this case, you get either a truthy value of yourValueX or the last falsy value.
Use an if-else-expression, also known as the conditional operator:
!isNaN(a) ? a : b
Try this:
var notNaN = [value1, value2, value3].find(item => !Number.isNaN(item))
This kind of operators use a lazy mechanism for their computation and this concept is called short circuting in javascript. Basically, JS returns value as soon as it feels no more computation is required to evaluate this expression. So, if its an && operator it will return as soon as it finds first non-truthy(0, "", null, undefined, NaN) as for && operator if any of the operands is non-truthy there is no point check rest of the operands as expression is already non-truthy, so it returns that value and exits, now if all the operands are truthy it checks till last and returns the last value. For || its just the opposite as soon as it finds first truthy value it returns otherwise keeps checking till last and returns it.
I am struggling with understanding how this snippet works on a basic level
if([] == ![]){
console.log("this evaluates to true");
}
Please help me understand where I got it wrong. My thinking:
First there is operator precedence so ! evaluates before ==.
Next ToPrimitive is called and [] converts to empty string.
! operator notices that it needs to convert "" into boolean so it takes that value and makes it into false then negates into true.
== prefers to compare numbers so in my thinking true makes 1 and [] is converted into "" and then 0
Why does it work then? Where did I get it wrong?
Why does it work then?
TLDR:
[] == ![]
//toBoolean [1]
[] == !true
[] == false
//loose equality round one [2]
//toPrimitive([]); toNumber(false) [3]
"" == 0
//loose equality round two
//toNumber("") [4]
0 === 0
true
Some explanations:
1)
First there is operator precedence so ! evaluates before ==
Negating something calls the internal toBoolean method onto that "something" first. In this case this is an Object (as Arrays are Objects) and for that it always returns true which is then negated.
2)
Now it's up to loose equalities special behaviour ( see Taurus answer for more info) :
If A is an Object ( Arrays are Objects ) and B is a Boolean it will do:
ToPrimitive(A) == ToNumber(B)
3)
toPrimitive([])
ToPrimitive(A) attempts to convert its Object argument to a primitive value, by attempting to invoke varying sequences of A.toString and A.valueOf methods on A.
Converting an Array to its primitive is done by calling toString ( as they don't have a valueOf method) which is basically join(",").
toNumber(false)
The result is 1 if the argument is true. The result is +0 if the argument is false. Reference
So false is converted to +0
4)
toNumber("")
A StringNumericLiteral that is empty or contains only white space is converted to +0.
So finally "" is converted to +0
Where did I get it wrong?
At step 1. Negating something does not call toPrimitive but toBoolean ...
The accepted answer is not correct (it is now, though), see this example:
if([5] == true) {
console.log("hello");
}
If everything is indeed processed as the accepted answer states, then [5] == true should have evaluated to true as the array [5] will be converted to its string counterpart ("5"), and the string "5" is truthy (Boolean("5") === true is true), so true == true must be true.
But this is clearly not the case because the conditional does not evaluate to true.
So, what's actually happening is:
1. ![] will convert its operand to a boolean and then flip that boolean value, every object is truthy, so ![] is going to evaluate to false.
At this point, the comparison becomes [] == false
2. What gets into play then is these 2 rules, clearly stated in #6 in the specs for the Abstract Equality Comparison algorithm:
If Type(x) is boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is boolean, return the result of the comparison x == ToNumber(y)
At this point, the comparison becomes [] == 0.
3. Then, it is this rule:
If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
As #Jonas_W stated, an array's ToPrimitive will call its toString, which will return a comma-separated list of its contents (I am oversimplifying).
At this point, the comparison becomes "" == 0.
4. And finally (well, almost), this rule:
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
An empty string converted to a number is 0 (Number("") == 0 is true).
At this point, the comparison becomes 0 == 0.
5. At last, this rule will apply:
If Type(x) is the same as Type(y), then
.........
If Type(x) is Number, then
.........
If x is the same Number value as y, return true.
And, this is why the comparison evaluates to true. You can also apply these rules to my first example to see why it doesn't evaluate to true.
All the rules I quoted above are clearly stated here in the specs.
First, realize that you are comparing two different types of values.
When you use ![] it results in false. You have code (at core it results in this):
if([] == false)
Now the second part: since both values are of different type and you are using "==", javascript converts both value type into string (to make sure that they have same type). It starts from left.
On the left we have []. So javascript applies the toString function on [], which results in false. Try console.log([].toString())
You should get false on the left as string value. On the right we have boolean value false, and javascript does the same thing with it.
It use the toString function on false as well, which results in string value false.
Try console.log(false.toString())
This involves two core concepts: how "==" works and associativity of "==" operator - whether it starts from left or right.
Associativity refers to what operator function gets called in: left-to-right or right-to-left.
Operators like == or ! or + are functions that use prefix notation!
The above if statement will result in false if you use "===".
I hope that helps.
It's said that non-empty string in Javascript is considered "truthy". It explains why the code:
if ("0") {
console.log("OK")
}
prints "OK".
However, why does the code:
true == "0"
returns false?
Equal (==)
If the two operands are not of the same type, JavaScript converts the
operands then applies strict comparison. If either operand is a number
or a boolean, the operands are converted to numbers if possible; else
if either operand is a string, the other operand is converted to a
string if possible. If both operands are objects, then JavaScript
compares internal references which are equal when operands refer to
the same object in memory.
(From Comparison Operators in Mozilla Developer Network)
So, while comparing true == '0', it first converts both into numbers.
Number(true) == Number('0') which evaluates to 1 == 0.
Hence the answer is false.
As others pointed out, I believe if ("0") will check if the value is null/empty/undefined, similarly as to if I were to write if("some text"), which would also return true. Here 0 is not used as true or false, but rather as a string.
On the other hand, if(true == "0") will return false, as the values do not match up.
Here is a snippet showing an if statement returning true on a variable that's not undefined.
var someVar = "0";
if("") {
console.log("this doesn't execute");
}
if(someVar) {
console.log("this returns true");
}
Given the following code:
if ("string") {
console.log('true!');
}
//logs "true" to the console
if ("string"==true) {
console.log('true!');
}
//doesn't log anything
Why does this happen? I thought "string" was being cast to a number, as is the boolean. So true becomes 1, and "string" becomes NaN. The second if statement makes sense, but I don't see why the first statement causes the inner loop to be evaluated. What's going on here?
It is being cast to Boolean. Any non-empty string evaluates to true.
From the ECMAScript Language Specification:
12.5 The if statement
Semantics
The production IfStatement: if ( Expression ) Statement else Statement is evaluated as follows:
Let exprRef be the result of evaluating Expression.
If ToBoolean(GetValue(exprRef)) is true, then
Return the result of evaluating the first Statement.
Else,
Return the result of evaluating the second Statement.
9.2 ToBoolean
The abstract operation ToBoolean converts its argument to a value of type Boolean according to Table 11:
Table 11 - ToBoolean Conversions
Undefined: false
Null: false
Boolean: The result equals the input argument (no conversion).
Number: The result is false if the argument is +0, -0, or NaN; otherwise the result is true.
String: The result is false if the argument is the empty String (its length is zero);
otherwise the result is true.
Object: true
As far as the == operator is concerned, it's complicated, but the gist of it is that if you compare a number to a non-number the latter is converted into a number. If you compare a boolean against a non-boolean, the boolean is first converted to a number, and then the previous sentence applies.
See section 11.9.3 for details.
// Call this x == y.
if ("string" == true)
// Rule 6: If Type(y) is Boolean,
// return the result of the comparison x == ToNumber(y).
if ("string" == Number(true))
// Rule 5: If Type(x) is String and Type(y) is Number,
// return the result of the comparison ToNumber(x) == y.
if (Number("string") == Number(true))
// The above is equivalent to:
if (NaN == 1)
// And NaN compared to *anything* is false, so the end result is:
if (false)
Non-empty strings are truthy, but are not necessarily equivalent to true.
== is a "soft" equality operator.
It uses type coercion to compare two equivalent objects as equal.
All of the following are true:
42 == "42"
0 == false
0 == ""
[] == ""
{} == "[object Object]"
"1" == true
Aribtrary strings are not equivlant to any primitive values.
However
When you write if (something), the if will execute if something is "truthy".
All values are truthful except the following:
false
0
NaN
""
null
undefined
if ("string"===true)
Should be written this way.
"string" is a string which is not null. In JavaScript everything not being null evaluates "true". So: if("string") is the same as if("string" != null) but "string" is not true, it is still a string value.
I think this is happening because in the first example, your "string" is a non-null object, which translates to true in this context, whereas in the second example, you're asking if this String object is the same as the Boolean object, which it's not, so it translates to false.
if ("string") {
console.log('true!');
}
As you may already know, if evaluates a boolean expression. So it checks
if((Boolean)"string")
Since (bool)string is true it passes. But in the case of
if ("string"==true) {
console.log('true!');
}
You are trying to equate a string with a bool, which obviously compares them and returns false.
Simple:
if("string") is evaluated as a boolean. Any value that isn't false is true, no conversion to number or anything of that sort.
Comparing "string" to a boolean value true will obviously yield false.
From the ECMA 262 reference, if you convert implicitly a String to Boolean, and the String is other than the empty String, it will evaluate to true.
Check here
I don't understand how &&, ||, and ! work... both with bools and other data types. How do you use them?
All values in JavaScript are either “truthy” or “falsy”.
a && b evaluates to the first falsy operand,
a || b evaluates to the first truthy operand.
Both operators will not evaluate any operands after the one the return.
If all operands don’t match, they will evaluate to the last one.
!a evaluates to true if a is falsy and false if a is truthy.
All values are truthy except the following, which are falsy:
null
undefined
false
+0
-0
NaN
0n
""
document.all
If you want to test that both of two conditions are truthy then use &&:
if (isX && isY)
{
// Do something.
}
If you want to test that one or both of two conditions are truthy then use ||:
if (isX || isY)
{
// Do something.
}
The ! inverts a boolean (a truthy value becomes false and vice versa).