

Silly Javascript - s3graham
http://blog.learnr.org/post/149021162/really-really-wtf

======
mustpax
First of all, I would strongly recommend you read Doug Crockford’s,
_JavaScript: the Good Parts_. JavaScript has a lot of quirks and rough edges,
but please do not try to use a language in a professional capacity without
learning it first. To be fair, JavaScript pretends to be Java just enough to
invite all this ill-advised behavior.

To answer the question fully: JavaScript arrays are really just plain objects.
All objects in JavaScript are simply associative arrays, and all associative
arrays are string indexed. So, subscripting always causes a string conversion.
The Array class provides some convenience methods with .push() .pop() to gloss
over this fact, but arrays are really no different than other objects.

~~~
boucher
I'm not a huge fan of Doug's book, but I think this is an excellent read:

[https://developer.mozilla.org/en/A_re-
introduction_to_JavaSc...](https://developer.mozilla.org/en/A_re-
introduction_to_JavaScript)

------
axod
Read a book on javascript.

"Javascript: The definitive guide" by O'Reily is the best.

This is not a quirk, Arrays are just objects with a special property 'length'
which is set to the highest key that can be converted to an integer, plus one,
and the array functions. All keys are however, strings, as with all objects.

For example,

    
    
      var arr = [];
      arr.foo = "hello";
      arr["hello"] = function() {};
      arr[40] = 56;
      // arr.length = 41
    

It's much easier when you understand that arrays in javascript don't exist as
a separate data type. They are, as I say, just objects with a couple of
convenience methods+length property.

------
eel
Yes, JavaScript arrays are not true arrays. Yes, all property names are
strings. If you use an integer as an index, it'll be converted to a string.

I suppose it's silly at first, but hopefully at some point, you grow used to
it. Crockford's book JavaScript: The Good Parts is a good book that explains
many of the oddities in JS.

------
halo
This functionality makes perfect sense as soon as you realise that at its core
JavaScript only has a single data structure, and that is objects (aka
dictionaries, associative arrays or hashmaps), and arrays are simply a special
case with some syntactic sugar built on top of it

I actually think that it's one of JavaScript's better ideas, it's just a shame
that the JavaScript doesn't have very strong getter/setter/subscripting
functionality so you could implement data structures like JavaScript arrays
completely in native JavaScript.

------
jrockway
This is the danger of syntax minimalism; using the same operator to refer to
elements of both arrays and dictionaries.

Perl has implicit type conversions similar to those of JavaScript, but the
syntax of the dereference operation makes it clear what's going on:

    
    
        $array[$number] $array[0] $array['0']
        $hash{$key} $hash{'42'} $hash{42}
    

Even without the obvious variable names, you can tell from the syntax what is
going to be converted to a number and what is going to be converted to a
string; [] means number and {} means string.

Javascript is stuck with the same syntax for both:

    
    
        array[number] array[42] array["42"]
        hash[key] hash[42] hash["42"]
    

which is apparently somewhat confusing. I know what is going to happen, but
the language doesn't help me; it's easy to write code that's misleading.

~~~
axod
Sorry, but that's wrong. I don't think there's any ambiguity at all. JS only
has string keys, and only has objects.

An array in js is just an object/dictionary, with a special 'length' property,
and a few convenience methods.

Further, the 'length' property can also be confusing to newcomers, since it
doesn't relate to the number of elements in the array, rather the maximum key
that can be converted to an integer +1.

For example,

var arr = []; arr.foo = "hello"; arr[4] = 56;

// arr.length = 5

It's much easier when you understand that arrays in javascript don't really
exist as a separate data type. They are, as I say, just objects with a couple
of convenience methods+length property.

~~~
s3graham
I think I agree with jrockway. I understand (now) that there's only string
keys in objects, but that's the random part. Why have [] syntax for "arrays"
then? It's the hashing behaviour that's the 'gotcha'.

Sure, x.a should stringize 'a' to make property access work cleanly, but why
when using the indexing syntax?

For example:

    
    
      sgraham@gerard:~$ lua
      Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
      > a = {}
      > a[0] = "wee"
      > a[1] = "waa"
      > a["1"] = "str"
      > print(a[0])
      wee
      > print(a[1])
      waa
      > print(a["1"])
      str
      > 
      > a["x"] = "wee"
      > a.x = "waa"
      > print(a["x"])
      waa
      > print(a.x)
      waa
      > 
    

which seems wholly more reasonable.

~~~
axod
>> Why have [] syntax for "arrays"

[] syntax is for objects and arrays. As I've said, an array is just an
object... Same data type.

If you didn't have a [] syntax, you wouldn't be able to use a variable to
reference properties on an object.

    
    
      var baz = "foo";
      foo.bar == foo["bar"] == foo[baz]

~~~
jrockway
So we're back to my main argument -- minimalism is confusing.

~~~
axod
If you're more used to complexity I guess :/

------
invisible
x is an Array (which should only accept numerics for keys). E.g. you cannot
have a String be a "key" in an Array.

However, for an Object (if they used {} instead of []), the property gets
converted using String() before being assigned, so you cannot have duplicate
values with the same String value. This actually makes sense when you consider
that JavaScript isn't a hard typed language and you often don't need to type
cast (which comes in handy more often than it fails a programmer).

My opinion: this guy is complaining just to complain, he could throw a _
before that 1 String and it solves his type problem completely.

~~~
axod
>> "x is an Array (which should only accept numerics for keys). E.g. you
cannot have a String be a "key" in an Array."

False. You can have anything you want in an Array, since it's just an object.

    
    
      var arr = [];
      arr["hello"] = 57;
      arr.world = function() {};
      arr[999.99] = "flibble!";
      arr[54] = 9;
      // arr.length now equals 55
    

May or may not be a good coding style, but that's a separate matter.

~~~
invisible
Agreed, just in a rush to comment before. I'd go one further and say using an
Array that way is just plain worrisome in JavaScript. It just breaks the
conceptual usage "sort of" of Array vs Object (for/while vs for each...in).
That's why a lot of frameworks add an "each" iterator for Array/Hashes (Hashes
being a "controlled" Object added by most frameworks).

------
palsecam
No way to avoid it, I think. Javascript calls Object.toString() to determinate
the key. But yes, kind of silly...

See <http://news.ycombinator.com/item?id=602004>

Actually there may be a way to avoid it: redefine the toString() method of the
String prototype or something like that (just an idea in the wild, haven't
tried it)...

------
skwaddar
Arrays are not hashes

~~~
tolmasky
It is reasonable to expect to be able to set arbitrary properties on an Array
and have them behave differently than it's indexes, despite the fact that this
is not how it works. The language even suggests this is possible by providing
certain properties that are not enumerated (such as "length"). What's worse is
that the true answer to why this behaves the way it does is that in JS arrays
_are_ (kind of) hashes.

~~~
invisible
Yes and no (as you said). Just expanding: Arrays are an instance of Object
with a few specialized methods. Therefore, you can (but should not) assign
keys with values to the array and it will apply correctly. However, then you
lose a great deal of the advantage of it being an Array.

------
polos
Try to use additional single quotes:

    
    
      var x = [];
      x['3'] = 3;
      x['"3"'] = "three";	    
      alert(x);

