If ([] == false) is true, why does ([] || true) result in []? - javascript

Was just doing some testing and I find this odd:
[] == false
Gives true, this makes sense because double equal only compares contents and not type and tries to do type-coercion. But if its comparing contents and returns true, that means [ ] is falsey (if you did [] == true you get false too), which means:
[] || false
Should give false, but it gives [ ], making it truthy? Why?
Another example:
"\n " == 0
Gives true, but "\n " || false gives "\n "? Is there an explanation for this or its just an oddity.
When I tried this in C, we get:
int x = "\n " == 0;
printf("%d\n", x);
int y = "\n " || 0;
printf("%d\n", y);
Outputs:
0
1
This makes sense, but given C's influence on Javascript, the behaviour is different.

Type conversion is not related to falsy and truthy values.
What is truthy and what is falsy is defined by the ToBoolean function defined in the specs and [] is indeed truthy.
On the other hand, [] == false returns true because of the type conversion that happens during the evaluation of the expression.
The rules of type conversion say that for x == y
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
ToNumber results in 0 for false so we're left with the evaluation of [] == 0. According to the same rules
If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
ToPrimitive results in an empty string. Now we have "" == 0. Back to our type conversion rules
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
ToNumber results in 0 for "" so the final evaluation is 0 == 0 and that is true!

"Is false" (even with coercion) is different from "evaluates as false in boolean context." obj == false asks if the object is the boolean value false, not whether it would evaluate as such if evaluated in boolean context.
You can evaluate an object in boolean context with (!!obj).
[] == false; // true
(!![]) == false; // false
"\n " == false; // true
(!!"\n ") == false; // false

from the ECMA-262 5.1 (page 83):
If ToBoolean(lval) is true, return lval
[] || false; // []

Related

Can't understand the conditional execution flow [duplicate]

This question already has an answer here:
Javascript equality operators
(1 answer)
Closed 3 years ago.
A simple js snippet. Why does it always alert
'result is empty'
As per my understanding, if block should get executed since result!="" is true and alert
'result is not empty'.
<script>
var result = false;
if(result != "")
alert('result is not empty')
else
alert('result is empty')
</script>
It's because != does implicit type conversion. If you used the strict version, !==, it would do what you expect. But the loose version, !=, will convert both of those operands to numbers, and both "" and false convert to 0, so "" != false is false, because it ends up (through a series of convolutions) being 0 != 0.
This is laid out in detail in Abstract Equality Comparison algorithm in the specification:
ReturnIfAbrupt(x).
ReturnIfAbrupt(y).
If Type(x) is the same as Type(y), then
Return the result of performing Strict Equality Comparison x === y.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
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).
If Type(x) is either String, Number, or Symbol and Type(y) is Object, then
return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String, Number, or Symbol, then
return the result of the comparison ToPrimitive(x) == y.
Return false.
As we can see from the above, if we start out with false and "", then:
We follow Step 8, convert false to 0, and start again with 0 != ""
We follow Step 6, convert "" to 0, and start again with 0 != 0
We follow Step 3 and get the result false (because we're doing !=, whereas the algorithm is defined in terms of ==).
In javascript two falsy things can be equal, as in this case, where result != "" yields false.
You need to use an strict comparison, i.e. !== to make the comparison. result !== "" yields true.
Javascript checks for truthy values.
false != ""
is false
false !== ""
is true so you can try it.

Javascript equality operators

In David Flanagan's Javascript guide, there is a statement:
the == operator never attempts to convert its operands to boolean
So here I did a little test:
var a = false;
var b = ""; // empty string
a == b; //returns true
Looking at Abstract Equality Comparison Algorithm there is a point:
e. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
How can x and y be both true if y is string data type (without conversion)?
What happens under the hood is
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
Number(false) == ""
followed by
If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
Number(false) == Number("") -> 0 == 0
How can x and y be both true if y is string data type (without conversion)?
They are not both true, but after type coercion their values are equal.
the == operator never attempts to convert its operands to boolean
And that is correct, if you check the comparison algorithm you will find that types are never implicitly casted to Boolean.
References:
11.9.3 The Abstract Equality Comparison Algorithm
9.3 ToNumber

When is (true == x) === !!x false?

JavaScript has different equality comparison operators
Equal ==
Strict equal ===
It also has a logical NOT ! and I've tended to think of using a double logical NOT, !!x, as basically the same as true == x.
However I know this is not always the case, e.g. x = [] because [] is truthy for ! but falsy for ==.
So, for which xs would (true == x) === !!x give false? Alternatively, what is falsy by == but not !! (or vice versa)?
"So, for which xs would (true == x) === !!x give false?"
Any x where its Boolean conversion is not the same as its conversion by the Abstract Equality Comparison Algorithm.
An example is a string with only whitespace:
var x = " ";
Its Boolean conversion is true (as is the case with any non-empty string), but its == comparison is false because a string with only white space will be converted to the number 0, and the true value will be converted to the number 1, and those values are not equal.
x == true; // false
!!x; // true
or to show the ultimate values the == is comparing:
Number(true) == Number(x);
// 1 == 0
1 == 0; // false
and to show the result of !!x, it would be equivalent to this:
Boolean(x); // true
So your original expression could crudely be seen as the following:
var x = " ";
(Number(true) == Number(x)) === Boolean(x);
// ( 1 == 0 ) === true
// ( false ) === true
false === true; // false
I say "crudely" because this certainly doesn't capture all the detail of the algorithm linked above, and won't be the same for all values provided to the operands.
To understand how == treats its operands, you really need to study the algorithm a bit.
Loose equality has nothing to do with truthiness.
The rules for loose equality basically involve comparing the results of the .valueOf() function for each object.
For more details, see the spec.

Is whitespace equals to integer 0 in Javascript?

My app behaves abnormally and figured the code below is going to else statement unexpectedly.
code
if(" " != 0) {
console.log("whitespace is not zero");
}
else {
console.log("bar");
}
Firebug output
bar
I thought whitespace is a String and comparison against integer zero should return false like the case above but I don't know why it is going to else statement.
Could anyone explain why?
In JS, " " == 0 equals true with loose/lenient comparison, you should use strict equality operator ===/!== instead:
" " !== 0
To get to first condition.
Tests:
console.log(" " == 0); // true
console.log(" " === 0); // false
Loose Comparison Chart:
"" == "0" // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
Strict Comparison Chart:
"" === "0" // false
0 === "" // false
0 === "0" // false
false === "false" // false
false === "0" // false
false === undefined // false
false === null // false
null === undefined // false
" \t\r\n" === 0 // false
(Examples by Douglas Crockford)
Good Practice:
Whenever possible, use strict equality operator because with loose equality operator, JS does type coercion which is a performance hit and doesn't always yield expected results as shown in above comparison charts.
The other answers have told you how to solve the issue. My answer will attempt to actually explain why you have the issue in the first place (since that was your actual question!)
The behaviour of the == operator is defined in the spec as the "abstract equality algorithm". It states (among other things) the following:
If Type(x) is String and Type(y) is Number, return the result of the
comparison ToNumber(x) == y.
One of the rules of the ToNumber operation on a string is as follows:
The MV of StringNumericLiteral ::: StrWhiteSpace is 0...
Once the exact MV for a String numeric literal has been determined, it is then rounded to a value of the Number type. If the MV is 0, then the rounded value is +0 unless the first non white space character in the String numeric literal is ‘-’, in which case the rounded value is −0.
So we are left with +0 == 0 which fits another rule of the abstract equality algorithm:
If x is the same Number value as y, return true.
This is the case because 0 is the same as +0. Even if one of the numbers was -0 it would return true:
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return
true.
When you use != rather than !==, JavaScript tries to coerce the values on either side to the same type. In this case, I think it converts both to numbers.
" " happens to be 0 as a number. (Try " " * 1. It evaluates to 0.)
This also works with other operators like > or *. So " " > -1 is true and " " * 100 is 0. This also means you can do neat stuff like "6" * "7" and get 42. Unfortunately, this breaks down with + since it is inexplicably overloaded to do both math and string concatenation.
I personally like all of this behavior except for +. Others' opinions vary.
to compare with the number 0, you must use the strict comparison ===
if(" " !== 0) {
console.log("whitespace is not zero");
}
else {
console.log("bar");
}
a "truth table" found here: Which equals operator (== vs ===) should be used in JavaScript comparisons?
because a string with whitespaces is converted to 0. So
To compare:
if(" " !== 0) {
....

JavaScript truthiness in boolean to numbers comparison

I'm new to JavaScript and I'm trying to learn it from internet resources. While I'm aware that there will plenty of cr*p material, one thing most people seemed to agree is the truthiness of things in JS (just to give a example go here)
Now I found this odd thing in my experiments:
(true == 2) is false. why?
As far as I know, 2 is a non zero number, so it should be evaluated as true.
This is because when either operand of an equality operator is a number, in nearly all cases the other operand is converted to a number and then the result is compared. So you're ending up comparing 1 (converted from true) with 2, not true with true. The only exceptions to that rule are null, undefined, and objects whose default value (see off-topic below) is null or undefined; comparing a number to those returns false (even though Number(null) is 0; don't ask).
Details in the specification, Section 11.9.3: "The Abstract Equality Comparison Algorithm". This was the text of that section as of ES 5.1, but that link is to the currently editor's draft (which is what each year's snapshot specification is based on) and there have been several :
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
If Type(x) is the same as Type(y), then
Return the result of performing Strict Equality Comparison x === y.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
NOTE: This step is replaced in section B.3.7.2.
If Type(x) is Number and Type(y) is String, return the result of the comparison x == ! ToNumber(y).
If Type(x) is String and Type(y) is Number, return the result of the comparison ! ToNumber(x) == y.
If Type(x) is BigInt and Type(y) is String, then
Let n be ! StringToBigInt(y).
If n is NaN, return false.
Return the result of the comparison x == n.
If Type(x) is String and Type(y) is BigInt, return the result of the comparison y == x.
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).
If Type(x) is either String, Number, BigInt, or Symbol and Type(y) is Object, return the result of the comparison x == ? ToPrimitive(y).
If Type(x) is Object and Type(y) is either String, Number, BigInt, or Symbol, return the result of the comparison ? ToPrimitive(x) == y.
If Type(x) is BigInt and Type(y) is Number, or if Type(x) is Number and Type(y) is BigInt, then
If x or y are any of NaN, +∞𝔽, or -∞𝔽, return false.
If ℝ(x) = ℝ(y), return true; otherwise return false.
Return false.
Note: The !s in the above are not negations, they indicate that the following abstract operation never results in an abrupt completion. Details in this article about reading the spec.
If you wanted to check that they were both truthy or both falsy, you could use the bang (!) or double-bang (!!) idiom to coerce them both to booleans:
var a = true,
b = 2;
alert(a == b); // "false", 1 !== 2
alert(!!a == !!b); // "true", true === true
alert(!a == !b); // "true", false === false
a = false;
b = 0;
alert(a == b); // "true", 0 === 0
alert(!!a == !!b); // "true", false === false
alert(!a == !b); // "true", true === true
...but usually using == or != with booleans isn't ideal. But it does come up.
I tend to use the double-bang, but in JavaScript there's no reason to over the bang. (There's an argument for the double over the single in some other languages, though it's a weak one related to consistency with if (!!x). In JavaScript you never need the double-bang in the if (x) case, so...)
(Off-topic: The default value of most JavaScript objects is a string, though frequently one like "[object Object]" that ends up being NaN if you convert it to a number; but constructor functions can override that behavior via valueOf and toString. The default value of host objects is up to the host environment.)
The boolean true constant is promoted to a number, that being 1.
With non-strict comparison (==) if the operands are not of the same type, they will be casted/coerced and strictly compared, with first preference being to numbers if either operand is a number or boolean (MDN).
So true == 2 evaluates to Number(true) === 2 which is 1 === 2, which is false.
Of course you can always force things to compare as you want them to, which is explicit and can solve hard-to-find problems later on:
true === Boolean(2) is true.

Categories