Why does 2 == [2] in JavaScript?

Why does 2 == [2] in JavaScript?

I recently discovered that 2 == [2] in JavaScript. As it turns out, this quirk has a couple of interesting consequences:
var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true

Similarly, the following works:
var a = { “abc” : 1 };
a[[“abc”]] === a[“abc”]; // this is also true

Even stranger still, this works as well:
[[[[[[[2]]]]]]] == 2; // this is true too! WTF?

These behaviors seem consistent across all browsers.
Any idea why this is a language feature?
Here are more insane consequences of this “feature”:
[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!

var a = [0];
a == a // true
a == !a // also true, WTF?

These examples were found by jimbojw http://jimbojw.com fame as well as walkingeyerobot.

Solutions/Answers:

Solution 1:

You can look up the comparison algorithm in the ECMA-spec (relevant sections of ECMA-262, 3rd edition for your problem: 11.9.3, 9.1, 8.6.2.6).

If you translate the involved abstract algorithms back to JS, what happens when evaluating 2 == [2] is basically this:

2 === Number([2].valueOf().toString())

where valueOf() for arrays returns the array itself and the string-representation of a one-element array is the string representation of the single element.

Related:  Get the Highlighted/Selected text

This also explains the third example as [[[[[[[2]]]]]]].toString() is still just the string 2.

As you can see, there’s quite a lot of behind-the-scene magic involved, which is why I generally only use the strict equality operator ===.

The first and second example are easier to follow as property names are always strings, so

a[[2]]

is equivalent to

a[[2].toString()]

which is just

a["2"]

Keep in mind that even numeric keys are treated as property names (ie strings) before any array-magic happens.

Solution 2:

It is because of the implicit type conversion of == operator.

[2] is converted to Number is 2 when compared with a Number. Try the unary + operator on [2].

> +[2]
2

Solution 3:

var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true

On the right side of the equation, we have the a[2], which returns a number type with value 2. On the left, we are first creating a new array with a single object of 2. Then we are calling a[(array is in here)]. I am not sure if this evaluates to a string or a number. 2, or “2”. Lets take the string case first. I believe a[“2”] would create a new variable and return null. null !== 2. So lets assume it is actually implicitly converting to a number. a[2] would return 2. 2 and 2 match in type (so === works) and value. I think it is implicitly converting the array to a number because a[value] expects a string or number. It looks like number takes higher precedence.

Related:  Workflow engine in Javascript [closed]

On a side note, I wonder who determines that precedence. Is because [2] has a number as it’s first item, so it converts to a number? Or is it that when passing an array into a[array] it tries to turn the array into a number first, then string. Who knows?

var a = { "abc" : 1 };
a[["abc"]] === a["abc"];

In this example, you are creating an object called a with a member called abc. The right side of the equation is pretty simple; it is equivalent to a.abc. This returns 1. The left side first creates a literal array of [“abc”]. You then search for a variable on the a object by passing in the newly created array. Since this expects a string, it converts the array into a string. This now evaluates to a[“abc”], which equals 1. 1 and 1 are the same type (which is why === works) and equal value.

[[[[[[[2]]]]]]] == 2; 

This is just an implicit conversion. === wouldn’t work in this situation because there is a type mismatch.

Related:  Pure Functions: Does “No Side Effects” Imply “Always Same Output, Given Same Input”?

Solution 4:

For the == case, this is why Doug Crockford recommends always using ===. It doesn’t do any implicit type conversion.

For the examples with ===, the implicit type conversion is done before the equality operator is called.

Solution 5:

[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!

That’s interesting, it’s not that [0] is both true and false, actually

[0] == true // false

It is javascript’s funny way of processing if() operator.

Solution 6:

A array of one item can be treated as the item itself.

This is due to duck typing. Since “2” == 2 == [2] and possibly more.