Why is "0" == [] false?

Truthy and Falsy As well as a type, each value also has an inherent boolean value, generally known as either truthy or falsy. Some of the rules are a little bizarre so understanding the concepts and effect on comparison helps when debugging JavaScript applications.

The following values are always falsy:

  • false
  • 0 (zero)
  • '' or "" (empty string)
  • null
  • undefined
  • NaN (e.g. the result of 1/0)

Everything else is truthy. That includes:

  • '0' (a string containing a single zero)
  • 'false' (a string containing the text “false”)
  • [] (an empty array)
  • {} (an empty object)
  • function(){} (an “empty” function)

Unexpected situations can occur when comparing truthy and falsy values using the == loose equality:

See the Loose Equality Comparison Table

Table for loose equality comparison with ==


/*
If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).
*/
console.log( 0 == '0');

/*
If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).
*/
console.log( 0 == [] );

/*
If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
*/
console.log( [] == '0');

source: http://es5.github.io/#x11.9.3


JavaScript will try to coerce types when using double equals operator (==). Exact details in spec: sec 11.9.3: Abstract Equality Comparison Algorithm.

Example 1:

console.log( 0 == '0' );     // true

JavaScript coerces the string to the number 0, so 0 == 0.

Example 2:

console.log( 0 == [] ); // true

An empty array's "ToPrimitive" value is zero, when comparing to a number. So this one reduces to 0 == 0.

Example 3:

 console.log( [] == '0' ); // false
 console.log( [] == '' ); // true

While the first one looks quite similar to the previous example, neither side is a number. At first glance this appears to be a truthy comparison, BUT [] is not one of the eight falsy values.
Demonstrating that [] is truthy, but '' is falsy:

 console.log( [] ? true : false ); // true
 console.log( '' ? true : false ); // false

In any sane language, the above two statements would imply that [] == '' would be false. But as we saw earlier, that isn't the case in JavaScript!

INEXPLICABLY, [] converts to false when using ==:

 console.log( [] == true ); // false
 console.log( [] == false ); // true

Conclusion: both sides are converted to booleans, but NOT by the "normal" "truthy/falsy" rule (which would convert [] to true, because it is not one of the eight falsy values). Instead, [] converts to false when using ==:

 console.log( [] == '0' ); // `false == true`, so false
 console.log( [] == '' ); // `false == false`, so true

Example 4:

 console.log( [0] == '' ); // false
 console.log( [1] == '' ); // false

This could EITHER indicate that the length of the array (1), which is "truthy", is compared to '', which is "falsy", so true == false, which is false. OR it could indicate that no type conversion is appropriate, which is case (10) in the spec, so false. BUT see example 5, which doesn't seem to fit either possibility.

Example 5:

 console.log( [0] == '0' ); // true
 console.log( [0] == '1' ); // false
 console.log( [1] == '1' ); // true
 console.log( [1] == '0' ); // false
 console.log( [2] == '2' ); // true
 console.log( [1] == '2' ); // false

Surprisingly, an array that contains one number, apparently is converted to that number, when comparing to a non-empty string. This then goes to the rule for comparing a number to string, which converts the string to a number. So we are comparing either (0 or 1 or ..) to (0 or 1 or ..).
Is this an ambiguity in the spec? Differs between different implementations?
Testing done at https://www.webtoolkitonline.com/javascript-tester.html on 2020-Oct-27, in Chrome on a Windows 10 pc, using alert instead of console.log.

Example 6:

If all the above doesn't convince you to never use == again, consider this:

var a = [];
console.log( a == a ); // true

BUT:

console.log( [] == [] ); // false

None of the 9 type conversion rules in the spec apply, so this is case 10: they aren't the same object, even though neither of them has any contents. They are two different instances of an empty array.


In all, this is why its generally safer to use triple equals, which checks type and equality.

A handy illustration (for the cases that test truthiness) below:

function truthyOrFalsy(val) {
    return val ? "Truthy" : "Falsy";
}

console.log("empty array:", truthyOrFalsy([]));
console.log("number zero:", truthyOrFalsy(0));
console.log("string with a zero character:", truthyOrFalsy("0"));

Tags:

Javascript