Why does [] == ![] return TRUE in JavaScript?

It’s hard to believe.

How can an Array not be an Array?

It makes no sense — [] is truthy and ![] should be false.

So how can [] equal false?

And this somehow doesn’t happen for other types like strings and numbers:

Are JavaScript arrays broken?

What happened here

Dump all the blame on the dangerous == operator.

This is just another instance of why we always tell new JavaScript devs to NEVER use it (ever).

Especially if they’ve already been coding with stubbornly strict languages like C#.

At first glance, it doesn’t seem like there’s anything wrong with ==:

Plain text
// C# int num = 2; Console.WriteLine(num == 10); // false Console.WriteLine(num == 2); // true
JavaScript
// JS let num = 2; console.log(num == 10); // false console.log(num == 2); // true

But now look what happens here:

Plain text
// C# int num = 2; // ❌ Error: can't compare int and string Console.WriteLine(num == "2"); // false

But look what happens in JavaScript:

JavaScript
// JS let num = 2; console.log(num == "2"); // true?

JavaScript auto-casts the string into a number!

This is one of the many frustrations people have with JavaScript that made TypeScript come along.

Instead of just failing and stopping us from doing dumb stuff, it just goes “Mhmm okay, if you say so…”

JavaScript
// Huh? console.log(null == undefined); // true // Converts array to string console.log([1,2,3] == "1,2,3"); // true (seriously?)

So what do you think REALLY happens in [] == ![], behind the scenes?

First of all, empty arrays are truthy in JavaScript, so ! acts on it to make it false

JavaScript
[] == false

So now surprise surprise, we suddenly find ourselves comparing an Array to Boolean. Obviously not gonna end well.

As we now know, JS doesn’t care so it just goes ahead — this time casting the Boolean to the equivalent number

JavaScript
[] == Number(false) [] == 0

Next, thanks to some garbage rules that you don’t need to ever know, [] turns into… an empty string?

JavaScript
// don't ask "" == 0

And now finally it converts "" into… a Number:

JavaScript
0 == 0 // true

So what’s the solution to avoid this nonsense?

Always use the strict equality operator === (and I mean always).

JavaScript
// font ligatures make triple equal look nicer console.log(2 == '2'); // ❌ true console.log(2 === '2'); // ✅ false console.log([] == ![]); // ❌ true console.log([] === ![]); // ✅ false

There is no scenario imaginable in the universe where == can be used that === can’t be

And now with ===, your lovely VS Code editor suddenly comes alive to stop us from doing something like this:

It still compiles though — unless you use TypeScript

But before it was asleep:

But what about [] == []?

Okay this makes sense, but what then could possibly explain this:

Surely the == can’t be blamed here. They have the same type, don’t they?

Yes they do.

The problem is that JavaScript compares arrays by reference. Not by value.

They may have exactly the same value, but as long they don’t refer the same object in memory, they will never be equal in the eyes of == and ===

JavaScript
// these are creating new array objects // on the fly, stored at different locations console.log([] == []); // false console.log([] === []); // false // store new object this time const arr = []; // reuse it const tari = arr; // both vars refer to the same object in memory console.log(arr == tari); // true console.log(arr === tari); // true

And this is how it is for objects in general too:

JavaScript
console.log({} === {}); // false const person1 = { name: 'tari ibaba' }; const person2 = { name: 'tari ibaba' }; const person3 = person1; // Only person1 and person3 point to the same object console.log(person1 === person2); // false console.log(person1 === person3); // true console.log(person2 === person3); // false

But of course, this isn’t the case for our core primitive values — strings, numbers, and booleans:

JavaScript
console.log('tari ibaba' === 'tari ibaba'); // As we saw previously console.log(2 === 2);

So what do you do when you want to compare arrays by their element values?

If it’s sorted you can use JSON.stringify():

JavaScript
function arraysEqual(array1, array2) { return JSON.stringify(array1) === JSON.stringify(array2); }

Otherwise, you go for the more generic length and every() combo:

JavaScript
function arraysEqual(array1, array2) { return ( array1.length === array2.length && array1.every((value, index) => value === array2[index]) ); }

Final thoughts

== is just one example of JavaScript’s looseness making it do things that make no sense in the real world.

Moral lesson: Always use strict equality, use TypeScript, and prioritize modern features.



Every Crazy Thing JavaScript Does

A captivating guide to the subtle caveats and lesser-known parts of JavaScript.

Every Crazy Thing JavaScript Does

Sign up and receive a free copy immediately.

Leave a Comment

Your email address will not be published. Required fields are marked *