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)...
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.
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.
I'd recommend "Javascript: The definitive guide" O'Reily far more. "The good parts" isn't really a full language spec. It's an interesting read, but not as useful IMHO
When assigning a String with a numeric value I think JavaScript treats it as a numeric for an Array and a String for regular Objects. This doesn't really change the difference, just that an Array should hold numerical index values (vs an Object key, but they CAN hold regular keys since they are an Object). A bit confusing I guess...
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.
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.
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.
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.
[] creates an Array (a special instance of an Object which has a completely different prototype). {} creates an Object with no special methods except ones that apply to all types in JavaScript. I'm pretty good at JS - I swear.
In general, most don't use the same String value for a key/index to store different values. Just my opinion on that one, though.
Oh, and: you can use Firebug to effectively see the difference between the two.
>>> x = ["1"];
["1"]
>>> x = {"1": "1"};
Object 1=1
Sorry, didn't mean to be a dick. :) This particular wart apparently got my nerd rage going.
> In general, most don't use the same String value for a key/index to store different values
Agreed, it'd generally be pretty sketchy. My current puttering around project is a "Python-in-JS" in the vein of http://objective-j.org/ which is where the desire for a "map" rather than an "object" comes from.
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).
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:
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.
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?
but the syntax of the dereference operation makes it clear what's going on
It makes it clear for trivial operations. Once you enter the realm of nested hashes (preferably with some arrays mixed in) the syntax turns into a royal pain in the ass.
"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.
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.
29 comments
[ 3.1 ms ] story [ 73.5 ms ] threadSee 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)...
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.
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.
https://developer.mozilla.org/en/A_re-introduction_to_JavaSc...
However, the same behavior is true of plain Objects.
What you're complaining about is similar to complaining that
"hello " + 3 + " world" == "hello " + "3" + " world"
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.
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.
[] and {} seem to be identical, except that [] one auto-increments a key-as-string in its initialization syntax.
Yes, an _ before the string would fix that particular interactive session, but it's not going to work in general.
In general, most don't use the same String value for a key/index to store different values. Just my opinion on that one, though.
Oh, and: you can use Firebug to effectively see the difference between the two.
Sorry, didn't mean to be a dick. :) This particular wart apparently got my nerd rage going.
> In general, most don't use the same String value for a key/index to store different values
Agreed, it'd generally be pretty sketchy. My current puttering around project is a "Python-in-JS" in the vein of http://objective-j.org/ which is where the desire for a "map" rather than an "object" comes from.
False. You can have anything you want in an Array, since it's just an object.
May or may not be a good coding style, but that's a separate matter.Perl has implicit type conversions similar to those of JavaScript, but the syntax of the dereference operation makes it clear what's going on:
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:
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.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.
Sure, x.a should stringize 'a' to make property access work cleanly, but why when using the indexing syntax?
For example:
which seems wholly more reasonable.[] 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.
It makes it clear for trivial operations. Once you enter the realm of nested hashes (preferably with some arrays mixed in) the syntax turns into a royal pain in the ass.
"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,
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.