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"" == 10 == 1Whereas 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 == yis 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