120

Boot up your interpreter/console and try the comparison:

> ",,," == Array(4)
True

Why? At first I thought maybe since you could think of ",,," as an array of four characters with a '\0' terminating slice, that might be why, but

> "..." == Array(4)

Returns "False". So... why? I know it's some idiosyncratic bit of duck typing in JavaScript, but I am just curious what underlines this behavior. I gleaned this from Zed Shaw's excellent presentation here, btw.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ZenLikeThat
  • 2,052
  • 3
  • 16
  • 23
  • 14
    Few languages apart from C use zero-termination in a way visible to the programmer. – Joey Jun 05 '12 at 21:39
  • 7
    If I may ask, what lead to this discovery? – SomeKittens Jun 05 '12 at 22:52
  • 1
    @SomeKittens Zed Shaw mentions this explicitly in the video I linked to in my question (as a criticism of Javascript). Cheers! – ZenLikeThat Jun 06 '12 at 02:23
  • 5
    @SomeKittens This is also mentioned in the (pretty well known) "wat" talk, showing some quirks in Ruby and JavaScript https://www.destroyallsoftware.com/talks/wat – Cronco Jun 06 '12 at 11:26
  • Type coercion is a hell of a feature: http://stackoverflow.com/questions/1724255/why-does-2-2-in-javascript – Xavi Jun 12 '12 at 17:20
  • another f**ed example from js, thanks:)! – Evgeny Jun 12 '12 at 18:03
  • 5
    This is one of many good reasons to always use `===` instead of `==`. – wprl Jun 12 '12 at 19:52
  • This works out to be true in this case, but you have to be careful. The only reason this ends up using String comparison is because the valueOf() method for arrays doesn't return a primitive type. ToPrimitive doesn't pass a type hint to \[\[DefaultValue\]\], so \[\[DefaultValue\]\] defaults to the Number (unless you're calling it on a Date). – pdpi Jun 15 '12 at 11:58

6 Answers6

177

Because the right hand operand is converted to a string and the string representation of Array(4) is ,,,:

> Array(4).toString()
  ",,,"

If you use the array constructor function and pass a number, it sets the length of the array to that number. So you can say you have four empty indexes (same as [,,,]) and the default string representation of arrays is a comma-separated list of its elements:

> ['a','b','c'].toString()
  "a,b,c"

How the comparison works is described in section 11.9.3 of the specification. There you will see (x == y):

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

(arrays are objects in JavaScript)

and if you follow the ToPrimitive method you will eventually find that it it calls toString.

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

Try using ===. When using == in JavaScript, it will attempt to cast the variables, thus leading to issues like this one. The console is casting Array(4) to the string representation (i.e., Array(4).toString), which is ",,,". The reason the commas are there is that the .toString() function adds them to separate items in an array.

See the snippet below:

document.write( Array(4).toString() );
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
SomeKittens
  • 38,868
  • 19
  • 114
  • 143
31

Internally, it’s going:

",,," == Array(4).toString()
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jason Kulatunga
  • 5,814
  • 1
  • 26
  • 50
18

This is because Array(4) initialises an array of 4 empty values, an == implicitly converts, so:

 ",,," == Array(4)

 ",,," == Array(4).toString()

 ",,," == ["", "", "", ""] // note 3 commas for 4 values

 ",,," == ["", "", "", ""].toString()

Are all similar.

== does implicit type conversions before comparing the values, which can result in unpredictable results. Use === to check the type and the value.

Keith
  • 150,284
  • 78
  • 298
  • 434
5

Comparing an Array to a string coerces the Array to a string before doing the comparison. Coercing an empty 4-element Array to a string yields that exact string.

Russell Borogove
  • 18,516
  • 4
  • 43
  • 50
4

I first thought it was something with the "prototype"... But after a little investigation, I reached a sad conclusion...

Apparently it is an internal and more obscure JavaScript thing with not much logic...

Just try

Array(4)==Array(4)

and no coercion on types also...

Array(4)===Array(4)

and you'll get FALSE.

You know that null==null, null===null and even undefined==undefined and undefined===undefined returns TRUE... so... it's a bit obscure...

Array(4)==[,,,] should also be true.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ZEE
  • 2,931
  • 5
  • 35
  • 47
  • ZEE, Array(4)==[,,,] wont be true. If we compare object with primitive, then the object will be converted into primitive. Thats the reason it calls toString(). – devsathish Jun 12 '12 at 18:57
  • array(x) should be the address of the constructor... anyway, in a system (dont bother what kind of system), === sould always be true! – ZEE Jun 15 '12 at 17:04