6

We all know javascript does funky conversions when testing for equality, but what exactly happens under the hood?

> [0] == 0
true
> 0 == [[0]]
true
> [0] == [[0]]
false

Yes, it was naive of me to expect transitivity from == operator.

Luboš Turek
  • 6,273
  • 9
  • 40
  • 50
  • 1
    "Yes, it was naive of me to expect transitivity from == operator." - indeed. There are plenty of examples – John Dvorak Dec 30 '14 at 10:20
  • Just a side note, read this too: http://stackoverflow.com/questions/7202157/why-is-10 This helped me a lot to understand why such conditions are either true, false, 1, 0 or whatever. – briosheje Dec 30 '14 at 10:31
  • related: http://stackoverflow.com/q/22231191/1048572 – Bergi Dec 30 '14 at 10:42

3 Answers3

7

[0] == 0 and 0 == [[0]] compares a primitive value with an object and thus type conversion will be performed. In both cases [0] and [[0]] will eventually be converted to the primitive value 0.

This is defined in steps 8 (and 9) of the The Abstract Equality Comparison Algorithm:

  1. If Type(x) is either String or Number and Type(y) is Object,
    return the result of the comparison x == ToPrimitive(y).

However, [0] === [[0]] compares two objects and two different objects are never equal to each other:

1f. Return true if x and y refer to the same object. Otherwise, return false.


Here is a slightly simper example that demonstrates that loose comparison is not transitive:

" " == 0 // true
"\n" == 0 // true
" " == "\n" // false

The first two comparisons perform type conversion (string to number), the last one does not and the values of both strings are different.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
2

Your first 2 examples implicitly converts the arrays to strings, then compares those to the 0:

var a = [0].toString(); // "0"
var b = a == 0 // "0" == 0; // true

The last example doesn't cast the arrays, it just compares the arrays' identities. These don't match, obviously, so false is returned.

The extra layer of depth you have in some of those arrays doesn't make a difference, in your examples:

[0] == [0]     // false, they're not the same array.
0 == [[[[0]]]] // true, [[[[0]]]].toString() === "0", "0" == 0

As @JanDvorak mentioned in a comment on @KooiInc's answer, behind the scenes, JS doesn't use toString for this conversion. However, in concept this is what's happening.

Community
  • 1
  • 1
Cerbrus
  • 70,800
  • 18
  • 132
  • 147
1

The behaviour is as per JavaScript The Abstract Equality Comparison Algorithm

  1. Comparing [0] == 0 - Operand types are different

Matches Case 9 of algo: Type(x) is Object and Type(y) is either String or Number
result: ToPrimitive(x) == y. i.e '0' == 0, hence true

  1. Comparing 0 == [[0]] - Operand types are different

Matches Case 8 of algo: If Type(x) is either String or Number and Type(y) is Object, result: x == ToPrimitive(y). i.e 0 == '0', hence true

  1. Comparing [0] == [[0]] - Operand types are same i.e object

Matches Case 1 of algo: Type(x) is the same as Type(y), if type is 'object' Return true if x and y refer to the same object. Otherwise, return false. i.e reference will be matched, hence false

Amitesh
  • 1,507
  • 1
  • 11
  • 19