28

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

Why does JavaScript evaluate the expression like this?

TheChetan
  • 4,440
  • 3
  • 32
  • 41
  • 3
    The number `0` is falsey, the string `"0"` is not. – Jamiec Oct 30 '17 at 12:32
  • Because true ('0') is not false ([]) –  Oct 30 '17 at 12:34
  • @Jamiec But if "0" isn't falsey, why is `"0" == false` => `true`? – Constantin Groß Oct 30 '17 at 12:34
  • 1
    `Boolean([])` returns `true` , not `false` – LiranC Oct 30 '17 at 12:34
  • @Jamiec is right. But Javascript will also try to convert one type to another in the case of == (that's why it's recommended to use ===) While it's not possible to convert a string to an array, it's surely possible to convert a string to an int. Thus, you still get true. Yes, Javascript does a lot of magic during simple equal comparison. – Swann Oct 30 '17 at 12:34
  • @Philicare That's genius. But why `'0'` is `true` and `[]` is `false`? – Hedegare Oct 30 '17 at 12:35
  • Sorry, flippant comment - fuller answer below. – Jamiec Oct 30 '17 at 12:35
  • 6
    For the same reason that `[] == false` and `![] == false`. ¯\\_(ツ)_/¯ – Siguza Oct 30 '17 at 12:37
  • but,console.log([]); not return false – Shijin TR Oct 30 '17 at 12:41
  • see http://dorey.github.io/JavaScript-Equality-Table/ ; tl;dr: JS `==` is not transitive (it's symmetric though); as such, `a == b` && `b == c` does not imply `a == c` –  Oct 30 '17 at 13:17
  • 1
    1. Ask a question about javascript conversions on SO 2. Profit – ghord Oct 30 '17 at 13:45
  • In my opinion this is the most correct answer: 1. Convert `[]` to primitive type: `[].toString() === ''`, `toString` is calling by [ToPrimitive](https://www.ecma-international.org/ecma-262/5.1/#sec-9.1) 2. now `[]` is `''` (empty string) '' == '0' // false When instead of `'0'` is `0`, then `''` (array) is also coverting to number `0`, thats why `0 == []` is `true`. Just read [this](https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3) – Илья Зеленько Apr 09 '19 at 10:29

4 Answers4

36

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"));
ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • Where can read about this? About how this conversion is happening? – TheChetan Oct 30 '17 at 12:40
  • @TheChetan [Truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) and [Falsey](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) on MDN is a good place to start. There are a massive amount of questions on stackoverflow on this confusiong subject too. – Jamiec Oct 30 '17 at 12:45
  • 2
    @TheChetan: My advice is not to learn about it, and instead to follow Douglas Crockford's advice always use `===` to avoid having to deal with this frequently eccentric behaviour. – Jack Aidley Oct 30 '17 at 13:15
  • 3
    -1 "both sides are falsey ... one is falsey the other is not" Nope, all lists in JavaScript are truthy, even the empty list. Falsiness really doesn't have much to do with it. – Arthur Tacca Oct 30 '17 at 13:21
  • @ArthurTacca Yep, the wording is probably misleading there. Can you word it better? Feel free to update the answer if you wish (more helpful to future visitors than just pointing out its wrong) – Jamiec Oct 30 '17 at 13:56
  • 6
    All three examples are slightly to very misleading: 1) both operands are converted to numbers, as you can see with `16 == "0x10"` or `NaN != "NaN"`. 2) Truthy/falsy has nothing to do with it; in fact `[]` *is* truthy. Both are again converted to numbers, which you can again see with `16 == ["0x10"]`. 3) Again truthy/falsy has nothing to do with it. Both are converted to strings, as you can see with `[1,2] == '1,2'`; the empty array is converted to the empty string, which is not equal to the string containing one `0`. – ETHproductions Oct 30 '17 at 13:58
  • Ive made some updates here, hopefully iron out some of those issues. – Jamiec Oct 30 '17 at 14:02
  • The first two examples are much better now IMHO. The third still needs a bit of work: JavaScript in fact *can* convert them to the same type, namely strings. – ETHproductions Oct 30 '17 at 14:05
  • "In all, this is why its generally safer to use triple equals, which checks type and equality." This is not accurate. source: YDKJS – atilkan Aug 23 '19 at 12:29
  • Submitting an edit for code snippet #3's explanation, and a spec link. As @ETHproductions points out, this isn't quite due to truthiness; adding a 4th code snippet to demonstrate that. – ToolmakerSteve Oct 27 '20 at 17:16
  • More detail about @localhoost's comment. *type and equality* is accurate description for comparing *"primitive"* values (except for `NaN===NaN` which is `false`), and for strings, **but not for** other non-primitives (which are only `===` when the same object, not merely the same contents). Spec: [11.9.6 The Strict Equality Comparison Algorithm](https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.6). – ToolmakerSteve Oct 27 '20 at 18:09
  • MDN provided a bit more detail as to why `[] == false` is TRUE - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean The reason for [] == false even though [] is truthy is: the comparison [] == false compares the value of [] to false. And to get the value of [], the JavaScript engine first calls [].toString(). That results in "", and that is what’s actually compared to false. In other words, [] == false is equivalent to "" == false. And "" is falsy — and so that’s what explains the behavior in the example. – chessplayer Nov 02 '21 at 02:33
7
/*
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

5

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 ==

Muhammad Ali
  • 129
  • 7
0

JavaScript uses type Type Conversion to coerce any value to a Boolean in contexts that require it, such as conditionals and loops.

In first case

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

javascript uses coerceing and converts both to number and compares . Now 0==0 so true is returned .

In second case

console.log( 0 == [] );

Both are falsy (A falsy value is a value that translates to false when evaluated in a Boolean context ) . So now comparing false == false , true value is returned .

In 3rd case

console.log( [] == '0'); 

[] is falsy and '0' is string , js is not able to coerce them to convert the to type which can be compared . so false is returned .

Sandip Kumar
  • 241
  • 3
  • 25
  • "such as conditionals and loops" — This is neither a conditional nor a loop. It is an equals operator. The first case will convert `'0'` to a number not a string. The second case will convert the array to a number. The third case will convert the array to to a string and compare them. https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3 – Quentin Oct 30 '17 at 13:47
  • https://developer.mozilla.org/en-US/docs/Glossary/Falsy – Sandip Kumar Oct 30 '17 at 14:10
  • That document says it applies in a Boolean context. == is not a Boolean context. – Quentin Oct 30 '17 at 14:11