I have two statements like this. Why do they both evaluate to false
?
console.log([] == true)
console.log(![] == true)
If [] == true
is false
shouldn't ![] == true
result to true
?
I have two statements like this. Why do they both evaluate to false
?
console.log([] == true)
console.log(![] == true)
If [] == true
is false
shouldn't ![] == true
result to true
?
It's the way coercion works.
The first step of coercion is to convert any non primitive types to primitive types, then using a set of rules convert the left, right or both sides to the same type. You can find these rules here.
In your case [] == true
, would pass through these 4 steps:
[] == true
[] == 1
"" == 1
0 == 1
Whereas based on operator precedence the !
in ![] == true
is executed first so the expression is converted to false == true
which is obviously false
.
You can try the live demo by Felix Kling to better understand how the sameness operator works.
The value ![]
is false
, because []
is an Object (arrays are objects) and all objects, not including null
, are truthy. So any array, even if it is empty will always be a truthy, and the opposite of a truthy is always false
. The easiest way to check if a value is a truthy is by using !!
.
console.log("![]: " + ![]);
console.log("!![]: " + !![]);
When you are using a loose comparison (using ==
instead of ===
) you are asking the JavaScript engine to first convert the values into the same type and then compare them. So what happens is the values get converted according to a set of rules, once they are the same type, they get compared though the same process as a strict equality check (===
). The first change that []
goes through is to get converted to a string, the string version of an empty array is an empty string ""
, the empty string is then converted to a number, the numeric value of an empty string is 0
, since the numeric value of true
is 1
and 0
!= 1
, the final output is false
.
console.log("[] == true => `" + ([] == true) + "`");
console.log("String([]) => `" + String([]) + "`");
console.log("Number('') => `" + Number("") + "`");
console.log("Number(true) => `" + Number(true) + "`");
As per the Abstract Equality Comparison Algorithm - http://es5.github.io/#x11.9.3
Types of x and y are checked when
x == y
is to be checked.If no rule matches, a false is returned.
[] == true
, rule 7 matches, so a result of [] == ToNumber(true)
is returned i.e. false
is returned. ![] == true
, because ![]
returns false
, and false == true
returns false
.To get opposite result for your second operation, add a precedence (i.e. wrap) to your expression with braces.
console.log(!([] == true)); // returns true
Put ![]
in the console. It's false
.
So ![] == true
is the same as false == true
, which is false
.
[] != true
is true
though
None of the answers so far has addressed the main problem. [Edit: This is no longer true. See Nick Zoum's answer.]
The question essentially is this:
[] == true
returns false
=> []
is not true
=> []
is false
(because something not true must be false)
=> ![]
should be true
, since negation of false
is true
. Then why does ![] == true
return false
?
[]
is actually truthy. (So ![]
is actually falsy.)
Still, [] == true
returns false
-- the reason is coercion. It's another of Javascript's gotchas.
When an array is checked for equality explicitly against a boolean value (that is, against true
or false
), its elements are first converted to strings and then joined together. An empty array therefore becomes ""
— therein lies the problem, because an empty string is falsy.
In brief, an empty array is truthy, but it's coerced (when being compared to a boolean value) to an empty string, which is falsy.
Note the following, which comes from https://www.nfriedly.com/techblog/2009/07/advanced-javascript-operators-and-truthy-falsy/
Arrays are particularly weird. If you just test it for truthyness, an empty array is truthy. HOWEVER, if you compare an empty array to a boolean, it becomes falsy:
if ( [] == false ) {
// this code runs }
if ( [] ) {
// this code also runs }
if ([] == true) {
// this code doesn't run }
if ( ![] ) {
// this code also doesn't run }
(This is because when you do a comparison, its elements are turned to Strings and joined. Since it's empty, it becomes "" which is then falsy. Yea, it's weird.)
Read https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
Rule in JavaScript for The Equals Operator (==)
if
type(x) type(y) result
1.x and y are the same type See Strict Equality (===) Algorithm
2.null Undefined true
3.Undefined null true
4. Number String x == toNumber(y)
5. String Number toNumber(x) == y
6. Boolean (any) toNumber(x) == y
7. (any) Boolean x == toNumber(y)
8.String or Number Object x == toPrimitive(y)
9.Object String or Number toPrimitive(x) == y
***10.otherwise… false