The Identity Crisis of JavaScript Arrays
I was recently watching a talk on JavaScript by Douglas Crockford during which he said something that I really like:
“Programming is really serious business and it should never be undertaken in ignorance, but, for some reason, JavaScript seems to promote that programming ignorance attitude.”
One of the reasons I believe that JavaScript promotes less than stellar programming practices is that it allows you to misuse facilities of the language and still have it perform in a way that makes sense. One of the biggest ways that I’ve seen JavaScript abused over and over and still have it behave exactly as expected and/or intended is with the native Array object.
JavaScript’s Array object is intended to be used in a similar way as other C-like language array facilities in that it should be used to store values in the structure such that they can be retrieved by the way of a corresponding numerical index. Additionally, JavaScript’s Array provides a set of additional methods that allow you to perform a set of other functions like concatenation, sorting, reversing, and joining.
Unfortunately, it is a seemingly common practice to instantiate an Array object and then treat it as an associative array - or hash table - even though the object provides no true functionality that lends itself to this behavior. For example, it’s not at all uncommon to see something like this:
var hashTable = new Array(); hashTable['Father'] = 'Anakin Skywalker'; hashTable['Son'] = 'Luke Skywalker'; hashTable['Daughter'] = 'Leia Organa'; hashTable['Mother'] = 'Padme Amidala'; // and so on...
Furthermore, when it comes to iterating through an associative array, you typically see a for...in loop being used:
for(var familyMember in hashTable) { // use the force with hashTable[familyMember] }
The problem with doing all of the above is that an Array object has been instantiated but absolutely no functionality associated with this object is being used. Proof of this can be seen if you attempt to call several properties on the object. For instance, calling hashTable.length on this structure will return zero.
It’s possible to add several new values indexed by unique integer values using classical subscripting or even the push method:
hashTable[0] = 'R2D2'; hashTable[1] = 'C3PO'; hashTable.push('Mara Jade');
Now calling hashTable.length on this object will return three even though a total of six elements appear to have been added to the collection. This is because there is no such thing as an associative array in JavaScript. Instead, the associative array behavior that you see above is actually a manipulation of JavaScript’s Object. Since JavaScript is a prototype-based language, all objects, and thus Array, inherit from Object in JavaScript. The array-like behavior that you’re seeing - accessing length, ordinal indexing, and using push() - is provided by the Array object.
So how is this associative array behavior possible? Every key/value pair that is being set is doing nothing more than assigning a value to a unique property on an instance of Object. Although the for...in loop appears to be iterating through the keys of the associative array, the loop is actually iterating over the properties of said object.
Ultimately, the practice of creating an array object and then treating it as an associative array is really doing nothing more than getting a reference to a new Array and then performing actions on it that could have been accomplished by simply instantiating an Object. The following code would provide the exact same behavior:
var hashTable = new Object(); // or var hashTable = {}; hashTable['Father'] = 'Anakin Skywalker'; ... for(var familyMember in hashTable) { ... }
Obviously, it’s possible to mix and match behavior such that you can create an array object, store values at unique ordinal indexes in typical array fashion, and also store values at unique character keys; however, I’d argue that this is severely blurring the lines of object responsibility. At this point, the question to ask is this: “Is your Array an array, or is your Array an object?”
Personally, I try to make sure that each object I create has a very clear purpose and that it fulfills just that. To that end, I believe that creating an Array, utilizing its features, and simultaneously manipulating properties on the base object is lazy programming. Furthermore, I’d argue that you’re abusing the language - just because you can get away with something doesn’t make it the thing to do. Let your arrays be themselves.


