Do the && and || operators convert their operands to booleans? - javascript

Flanagan's O'Reilly JavaScript book states:
Unlike the && and || operators, the ! operator converts its operand to
a boolean value [...] before inverting the converted value.
If those logical operators don't convert the operands to booleans, how can the expression be evaluated?

They do convert the values to boolean, but only to determine how to proceed in evaluating the expression. The result of the expression is not necessarily boolean (in fact, if neither of your operands are boolean, it will not give you a boolean):
var x = false || 'Hello' // gives you 'Hello'
var y = 0 && 1 // gives you 0, because 0 is "falsy" and short circuits
var z = 1 || 2 // gives you 1, because 1 is "truthy" and short circuits

Per specification, section 11.11: Binary Logical Operators:
The production [of evaluating &&] ... is evaluated as follows:
Let lref be the result of evaluating LogicalANDExpression.
Let lval be GetValue(lref).
If ToBoolean(lval) is false, return lval.
Let rref be the result of evaluating BitwiseORExpression.
Return GetValue(rref).
The production [of evaluating ||] ... is evaluated as follows:
Let lref be the result of evaluating LogicalORExpression.
Let lval be GetValue(lref).
If ToBoolean(lval) is true, return lval.
Let rref be the result of evaluating LogicalANDExpression.
Return GetValue(rref).
So internally the value is "converted to a boolean". However, since this is never exposed -- and the entire semantic explanation is an abstraction which can be/is "optimized out" -- the behavior of && and || can be simply explained through using truthy-and-falsy values (for which ToBoolean covers: a truthy-value is one for which ToBoolean returns true, all other values are falsy).
The logical table for && is:
a b result
truthy any b
falsy any a
The logic table for || is:
a b result
truthy any a
falsy any b
Note that either the evaluation of a or b is returned.
Happy coding.
For completeness, from section 9.2:
The abstract operation ToBoolean converts its argument to a value of type boolean as ...
Undefined - false
Null - false
boolean (not Boolean object!) - The result equals the input argument (no conversion).
number (not Number object!) - The result is false if the argument is +0, -0, or NaN; otherwise the result is true.
string (not String object!) - The result is false if the argument is the empty String (its length is zero); otherwise the result is true.
Object - true

The operands are interpreted as booleans for evaluating the expression, but the return value of && or || is always one of the operands.
For example:
true && 0 === 0, not false
1 || false === 1, not true

Because JavaScript has an idea of truthiness that covers more than booleans.

Related

If an array is truthy in JavaScript, why doesn't it equal true?

I have the following code snippet:
if([]) {
console.log("first is true");
}
The console says first is true which means [] is true. Now I am wondering why this:
if([] == true) {
console.log("second is true");
}
and this:
if([] === true) {
console.log("third is true");
}
are not true. If the console logged first is true in the first snippet, that means [] should be true, right? So why do the latter two comparisons fail? Here is the fiddle.
This is by specification. By the ECMAScript 2015 Language Specification, any object that is implicitly coerced into a boolean is true; that means objects are truthy. Inside of an if statement, the condition, once evaluated and if not already boolean, is coerced into a boolean. Thus, doing:
if([]) {
...
}
[] is truthy when coerced to a boolean and is true.
On the other hand, when you try to compare two values of differing types with abstract comparison, ==, the engine must internally go through an algorithm to reduce the values to similar types, and ultimately integers that it can compare. In Section 7.2.12 of the specification on the steps for Abstract Equality Comparison x == y, it states:
7.2.12 Abstract Equality Comparison
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
[...]
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
Thus, the y operand (in this case true) is converted to 1 by coercion with ToNumber since it is a boolean, and [] == 1 is false because:
If Type(x) is Object and Type(y) is either String, Number, or Symbol, then
return the result of the comparison ToPrimitive(x) == y.
This will convert the x operand to a string with the toString method of the array, which is "" for an empty array in this case. After going through ToPrimitive, it will result in:
if("" == 1) {
...
}
And finally:
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
Thus, ToNumber of an empty string "" is 0 and you get:
if(0 == 1) {
...
}
And 0 does not equal 1, thus it is false. Remember that just because something is truthy, does not make it equal to true. Just try Symbol() == true or ({}) == true.
The final comparison, with === is strict comparison, and does not coerce any operands and will return false if both operands are not the same type. Since the left operand is an object (an array) and the right is a number, the comparison evaluates to false.
You have force type coercion before making a Boolean equity check with the Object types.
while "" == false // <- true or 0 == false // <- true works out well
with the Object types it doesn't
null == false // <- false
so you better do like
!!null === false // <- true or !![] === true // <- true
This is strict equality. It meas that both operands should be the same thing. In the case of object, they should be exactly the same object. Comparison between object with the same structure and the same values will fail, they need to be reference to the same object to success.
if([]===true){
console.log("third is true");
}
In case of operands of different types, than the comparison between them becomes strict. This leads to the case above.
if([]==true){
console.log("second is true");
}
Also, in the first if statement, [] is automatically casted to boolean true.
Boolean([]) is trying to ascertain whether the operand is truthy or not. Similarly, if([]) console.log('truthy') is checking whether the expression is truthy or not.
However, true == [] does not immediately decide to check truthiness. Instead, it follows the == weak equality checking rules.
The rule for true == [] is:
If one of the operands is an object and the other is a primitive,
convert the object to a primitive.
Objects (including arrays) are converted into primitives by calling the ##toPrimitive method on the object. This method does not exist on regular arrays and objects, but will exist if you add it to an object or declare it as a method of the class of an object.
During the weak equality type coercion, the hint sent to the ##toPrimitive method is 'default'. However, in other situations, a different hint is provided, allowing the object to coerce to different primitives in different situations.
const a = []
const b = []
b[Symbol.toPrimitive] = function (hint) {
if(hint==='number') return 3;
if(hint==='string') return 'hello'
else return false; // happens when hint is 'default'
}
const log = x=>console.log(x)
log(a==true) // false - a has no toPrimitive function
log(a==false) // false - a has no toPrimitive function
log(b==true) // false - toPrimitive returns false
log(b==false) // true - toPrimitive returns false
log(!b) // false - checks for truthiness, and objects are truthy
log(Boolean(b)) // true - checks for truthiness, and objects are truthy
log(b==3) // false - toPrimitive with hint=default returns false
log(Number(b)) // 3 - toPrimitive with hint=number returns 3
log(b=='hello') // false - toPrimitive with hint=default returns false
log(String(b)) // 'hello' - toPrimitive with hint=string returns 'hello'
log(+b) // 3 - `+` calls toPrimitive with hint=number,
// which returns 3
log(b+"") // 'false' - toPrimitive with hint=default returns false
log(`${b}`) // 'hello' - template literals call toPrimitive with
// hint=string, which returns 'hello'

Javascript : Strange behaviour `empty string` AND `false` returns empty string

Today I came across the strange behaviour in Javascript. Below is the code
return "" && false
returns "".
Why it behaves so ?
Because
The production LogicalANDExpression : LogicalANDExpression && BitwiseORExpression is evaluated as follows:
Let lref be the result of evaluating LogicalANDExpression.
Let lval be GetValue(lref).
If ToBoolean(lval) is false, return lval.
Let rref be the result of evaluating BitwiseORExpression.
Return GetValue(rref).
ECMAScript 5.1
This means:
Return the first value if it is falsy, return the second value if the first is truthy.
This is also the behavior seen if you do:
return false && true
You get false.
This means also that this
return 23 && "Hello"
would give you "Hello"
The LHS is run first and the return exits you from the function

Why zero is not taken into account to calculate in OR condition and is taken into account to calculate in AND condtion?

Why not zero - which is not a boolean - but a number?
Suppose this example:
var current = 0;
current += Number(3) || Number(4); // now current is 0 + 3 = 3
var current = 0;
current += Number(-3) || Number(4); // now current is 0 + -3 = -3
var current = 0;
current += Number(0) || Number(4); // now current is 0 + 4 = 4
So, in my example it's taking the value to be added which number is not zero.
So, my question is why actually the OR operator || is only taking the value to calculate is rather than zero?
And also,
var current = 0;
current += Number(0) && Number(3); // now current is 0
var current = 0;
current += Number(3) && Number(5); //now current is 5
I'm really confused how the AND and OR operators are working here with the number types (not a Boolean).
Logical operators evaluate both the left and right expressions (if necessary). They both short-circuit immediately. It means that, if the first expression itself is enough to produce the result, irrespective of the other expression, then the other expression will not be evaluated at all. For example, in OR operator, if the first expression is Truthy, then we don't have to evaluate the other expression, the same way, in AND operator, if the first expression is Falsy, we don't have to evaluate the other expression.
Now, we are talking about Truthy and Falsy, right? What are they? When we evaluate an expression, the Truthiness is determined by the following table as per ECMA 5.1 Standard specification,
+-----------------------------------------------------------------------+
| Argument Type | Result |
|:--------------|------------------------------------------------------:|
| 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 |
+-----------------------------------------------------------------------+
So, unless the number is +0, -0 or NaN, it will be considered Truthy. You can confirm that like this
console.log(Boolean(0));
# false
console.log(Boolean(-1));
# true
console.log(Boolean(100));
# true
That is why OR operator takes the value of the non-zero number.
Quoting from the ECMA 5.1 Specifications for OR Operator,
LogicalANDExpression :
BitwiseORExpression
LogicalANDExpression && BitwiseORExpression
LogicalORExpression :
LogicalANDExpression
LogicalORExpression || LogicalANDExpression
The production LogicalANDExpression : LogicalANDExpression &&
BitwiseORExpression is evaluated as follows:
Let lref be the result of evaluating LogicalANDExpression.
Let lval be GetValue(lref).
If ToBoolean(lval) is false, return lval.
Let rref be the result of evaluating BitwiseORExpression.
Return GetValue(rref).
The production LogicalORExpression : LogicalORExpression ||
LogicalANDExpression is evaluated as follows:
Let lref be the result of evaluating LogicalORExpression.
Let lval be GetValue(lref).
If ToBoolean(lval) is true, return lval.
Let rref be the result of evaluating LogicalANDExpression.
Return GetValue(rref).
NOTE The value produced by a && or || operator is not necessarily of type Boolean. The value produced will always be the
value of one of the two operand expressions.
The value of an OR statement is determined the moment you encounter "true" (something other than zero.. 'truthy'). Until you encounter that, you need to keep going: maybe one of the other terms is true?
This explains the behavior you are seeing.
current += Number(3) || Number(4) - 3 is true, condition met, no need to look at next term
current += Number(0) || Number(4) - 0 is false, keep going, 4 is true, condition met
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators
Logical operators are typically used with Boolean (logical) values;
when they are, they return a Boolean value. However, the && and ||
operators actually return the value of one of the specified operands,
so if these operators are used with non-Boolean values, they may
return a non-Boolean value.
I think zero is set to be falsy condtion and all others are set to be truthy condition while we use AND or OR operator for Number.
Consider the following what value does it take to calculate:
Remember 0 is false and all other values (including negative values) are true while we take number.
Also, suppose the followings are the numbers not the booleans.
5 || 0 // true || false returns true, so takes 5
0 || 3 // false || true returns true, so takes 3
4 && 0 // true && false returns false, so takes 0
0 && 6 // false && true returns false, so takes 0
2 && 3 // true && true returns true, which value would take????
// Ummm, last defined value, huh i.e. 3

What's wrong with != '' in javascript (comparing to an empty string)?

jsbin started warning me that x != '' is not good, and I should replace it with x !== ''
Why?
var x = false;
console.log(x !== ''); //true
console.log(x != ''); //false
In other words, false (and other falsy values, like 0) will coerce to an empty string. The !== and === operators (strict equality operators) ensure that the things being compared are of the same type.
To expand upon why this is the case, you need to head to the spec (linked to by T.J. Crowder in the comments). The section on the "Abstract Equality Comparison Algorithm" tells us the following:
If Type(x) is Boolean, return the result of the comparison ToNumber(x)
== y.
The section on ToNumber tells us:
The result is 1 if the argument is true. The result is +0 if the
argument is false.
In the example above, the argument is false, so we are now comparing +0 != ''. When comparing a number to a string, the following rule is followed:
If Type(x) is Number and Type(y) is String, return the result of the
comparison x == ToNumber(y).
Calling ToNumber on an empty string results in +0, just as it did for false:
A StringNumericLiteral that is empty or contains only white space is
converted to +0.
Now we are comparing +0 != +0, so we enter the "x and y are of the same type" section, which tells us:
If x is the same Number value as y, return true.
So +0 is equal to +0 and since we are using != it returns false.

|| converting empty string to bool, && not

Is this normal? Is it a feature or a bug? (I'm using firebug):
>>> '' || true
true
>>> '' || false
false
>>> '' && false
""
>>> '' && true
""
It is not converting the empty string to Boolean.
With ||
It is evaluating the left hand side, of which an empty string is falsy. It then checks the right hand side (because it's an or, and that side may be true), and returns that value.
With &&
Because && needs both sides to be true and the left hand side is falsy, it doesn't bother checking the right hand side (short circuit evaluation). Therefore, it just returns the left hand side, which is the empty string.
JavaScript always returns the last value it evaluated.
>>> '' || 0 || undefined || null || false || NaN || 'hello'
"hello"
It's not that one is converting and the other isn't; the lines with || are returning their second operand and the lines with && are returning their first, due to short-circuiting.
[ECMA-262 11.11]: Semantics
The production LogicalANDExpression : LogicalANDExpression &&
BitwiseORExpression is evaluated as follows:
Let lref be the result of evaluating LogicalANDExpression.
Let lval be GetValue(lref).
If ToBoolean(lval) is false, return lval.
Let rref be the result of evaluating BitwiseORExpression.
Return GetValue(rref).
The production LogicalORExpression : LogicalORExpression ||
LogicalANDExpression is evaluated as follows:
Let lref be the result of evaluating LogicalORExpression.
Let lval be GetValue(lref).
If ToBoolean(lval) is true, return lval.
Let rref be the result of evaluating LogicalANDExpression.
Return GetValue(rref).
The LogicalANDExpressionNoIn and LogicalORExpressionNoIn
productions are evaluated in the same manner as the
LogicalANDExpression and LogicalORExpression productions except
that the contained LogicalANDExpressionNoIn,
BitwiseORExpressionNoIn and LogicalORExpressionNoIn are evaluated
instead of the contained LogicalANDExpression, BitwiseORExpression
and LogicalORExpression, respectively.
NOTE The value produced by a && or || operator is not necessarily
of type Boolean. The value produced will always be the value of one of
the two operand expressions.
The || operator will return the first value which is truthy.
The && operator will return the second value if the first is truthy, otherwise it returns the first.
For more info, you can see the Logical Operators page on the MDC site.
In your case,
'' || true; '' is false, so the || operator moves onto the second value, which is true, and so returns it.
'' || false; '' is false, so the || operator moves onto the second value, which is false, and has no more values to compare, so returns it.
'' && false; the first value ('') is falsy, so it returns it.
'' && true; the first value ('') is falsy, so it returns it.

Categories

Resources