Why [] == false returns true
[] == false returns true because loose comparison makes JavaScript coerce both sides to a number, and it ends up comparing 0 == 0. Along the way the array becomes an empty string and the empty string becomes zero, so the equality turns out to be true even though nothing meaningful is equal here.
Theory
TL;DR
==triggers type coercion,===does not.- A boolean operand in a
==comparison is always turned into a number first:falseis0. - An object (and an array is an object) is coerced to a primitive through
valueOf(), thentoString(). [].toString()gives the empty string'', andNumber('')gives0.- So the expression reduces to
0 == 0, which istrue. [] === falseisfalse, because strict comparison performs no coercion.
Quick example
console.log([] == false); // true
console.log([] === false); // false
// The same chain, written out by hand:
console.log(Number(false)); // 0
console.log([].toString()); // ''
console.log(Number('')); // 0
console.log(0 == 0); // trueStep by step explanation
Take the expression:
[] == falseStep 1. == triggers type coercion. In a loose comparison JS tries to coerce the types so that the comparison becomes possible. The abstract equality algorithm in the ECMAScript specification states the rule as:
If one of the operands is of type
boolean, it is converted to a number.
Step 2. Convert false to a number.
false -> 0Now the expression looks like this:
[] == 0Step 3. An object (an array) on the left, a primitive on the right. If one of the operands is an object, it is first coerced to a primitive (through valueOf(), then toString()). For the array []:
[].toString(); // ''So:
[] -> '' // empty stringAnd now we have:
'' == 0Step 4. Comparing '' == 0. By the same algorithm:
If one operand is a string and the other is a number, the string is converted to a number.
Number('') -> 0So:
0 == 0The result:
trueSummary of the steps
| Stage | Expression | What happened |
|---|---|---|
| 1 | [] == false | false -> 0 |
| 2 | [] == 0 | [] -> '' |
| 3 | '' == 0 | '' -> 0 |
| 4 | 0 == 0 | true |
Why this is dangerous
This logic makes == unpredictable. Here are more examples of the same mechanism:
[] == ![] // true
'' == 0 // true
'0' == 0 // true
null == undefined // true
[] == '' // true
[0] == 0 // true
[1] == 1 // true
[2] == 2 // trueThe first line is the most telling one: ![] is false (an array is always truthy, so negating it gives false), then the familiar chain runs and [] == ![] also becomes true. A value equals its own negation, and that is perfectly legal JavaScript.
How to avoid the confusion
Use strict comparison ===, which performs no implicit type conversion.
[] === false // false
'' === 0 // false
null === undefined // falseA short recap:
| Expression | What JS does | Result |
|---|---|---|
[] == false | [] -> '' -> 0, false -> 0 | true |
[] === false | Compares without coercion | false |
If you need to check whether an array is empty, check it explicitly:
if (items.length === 0) {
// empty array
}Common mistakes
- Checking an array for emptiness by comparing it with
falseor0. It works by accident and breaks as soon as the value becomesnullor an object. Checkitems.length === 0instead. - Reading
[] == falseas "an array is falsy". An empty array is in fact truthy: the body ofif ([])runs. The falsiness here appears only because==coerces it to a number. - Mixing up
==and===in null checks. Here==is occasionally useful:x == nullcatches bothnullandundefined. But that is the one exception, and it should be used deliberately. - Relying on
valueOf()for arrays. For a plain arrayvalueOf()returns the array itself, which is not a primitive, so the engine falls through totoString(). OverridevalueOf()and the comparison result changes. - Ignoring the linter. The ESLint
eqeqeqrule bans==precisely because of cases like this, and turning it off for "shorter code" is not worth it.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.