Why do both "[] == true" and "![] == true" evaluate to false?

Viewed 947

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?

5 Answers

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:

  1. [] == true
  2. [] == 1
  3. "" == 1
  4. 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.

In more words:

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.

  1. For [] == true , rule 7 matches, so a result of [] == ToNumber(true) is returned i.e. false is returned.
  2. Reason you're getting the same result for ![] == 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

Related