« Well Said | Main| Ghostin' the Machine? »

Javascript isArray(): How to determine if an object is an array

QuickImage Category Show-n-Tell Thursday Technical Javascript SSJS

Javascript is an incredibly powerful language. Much of this power is derived from Javascript's incredible extensibility, and extremely loose (some would say nonexistent) data typing. Variables can be switched from strings to objects to simple types to ...well, whatever you want. Functions can be objects, objects can be functions, variables can be functions, etc. This can turn developers into Djinn, giving us phenomenal cosmic powers; without necessarily being bound to an itty-bitty living space.

All this power does come with a cost though, which is mostly measured in bottles of Excedrin. Sometimes doing things that seem very simple and safe on the surface lead us to forget the Cthuluean Terrors hiding in the darkness below.

Arrays are one of these things. They seem simple; but the potential nastiness they contain can drive you mad.

Rule 1: An array is an object as an enumerated list of variables.

Memorize that. All arrays are objects. All arrays are enumerated lists.... of variables. Variables can be anything (strings, numbers, objects, functions, arrays....).

Rule 2: Javascript Arrays are not Associative.

An Associative Array is a list of variables which is indexed by keys. These keys can be numbers, strings, or other objects. The critical difference here is that a Javascript array is enumerated by number, and an associative array is indexed by anything. Because Javascript is so extensible, and because all Javascript arrays are themselves objects, it is very easy to construct something that appears to be and associative array:

1) var myArray = new Array();
2) myArray[0] = "canned ham";
3) myArray[1] = "buttermilk";
4) myArray[2] = new Array(myArray[0], myArray[1]);
5) myArray["shopping list"] = myArray[2];

The above code will run just fine, but don't make the mistake of believing that this proves associative arrays are supported. Allow me to walk you through the code and explain what is happening.

Line 1) This declares the variable object myArray and instantiates it as an Array.

Lines 2 & 3) These lines add a couple of elements to myArray. When line 3 completes operation, myArray is an Array containing 2 elements. myArray's length property returns 2. myArray is an enumerated list of variables; the type of myArray's length property is number, and every value in the index is numeric.

Line 4) This looks kind of complicated, but actually isn't that big of a deal. This line adds a new element to myArray. This new element is itself a new Array, and is instantiated and populated with the first two elements from myArray. When line 4 completes operation, myArray is an Array containing 3 elements. myArray's length property returns 3. myArray is an enumerated list of variables; the type of myArray's length property is number, and every value in the index is numeric.

Line 5) This is where things break down. Line 5 adds a new element to myArray. The new element is nothing more than a pointer to myArray[2]. This itself is not a problem. The gotcha here is the assignment of the index value. Instead of assigning a number as the index value, we are assigning a string. The code works just fine, but myArray has changed from a true Array to an object.
When line 5 completes operation, myArray is an Object List containing 4 elements. myArray's length property returns 3. (Go ahead, test it yourself). This can lead to all kinds of problems if you are relying on the length property to determine the number of elements in the "Array". The length property of an Array returns the number of elements in the array. The length property of an Object returns the number of enumerated elements. myArray is a non-enumerated list of variables; the type of myArray's length property is still number, however the values in the index are no longer all numeric.

Using an "associative array" object in Javascript is normally not a problem, as long as you remember that such an object is not a true array. This, after all, is the core principle that makes JSON work. But sometimes we need to know if some object we are working with is a true array.

How can we test an object to determine if it is a true Array?

Answering that question is the ultimate reason for this post. Here are two functions that you can use to determine if the object you are working with is a true Array. The first ( isNumeric() ) is simply a helper function that determines if something is numeric. You could try using isNaN(); however doing so can sometimes lead to misinterpreted results. (Try using isNaN(null) as an example).
The second ( isArray() ) will tell you if the passed in object is a true Array.

Enjoy.

function isNumeric(obj) {
   try {
     return (((obj - 0) == obj) && (obj.length > 0));
   } catch (e) {
     return false;
   } // try
} // isNumeric()

function isArray(obj) {
   if (!obj) { return false; }
   try {
     if (!(obj.propertyIsEnumerable("length"))
       && (typeof obj === "object")
       && (typeof obj.length === "number")) {
         for (var idx in obj) {
           if (!isNumeric(idx)) { return false; }
         } // for (var idx in object)
         return true;
     } else {
       return false;
     } // if (!(obj.propertyIsEnumerable("length"))...
   } catch (e) {
     return false;
   } // try
} // isArray()


-Devin

Comments

Gravatar Image1 - Javascript sucks. Emoticon

Gravatar Image2 - function isArray(testObject) {
return (testObject.constructor == Array);
}
// isArray([]) returns true, isArray({}) returns false

OR

Object.prototype.isArray = function() {
return (this.constructor == Array);
}
// [].isArray() returns true, {}.isArray() returns false

Emoticon

Gravatar Image3 - Hey there Tim.
Your code is nice, and works fine in the test condition.....right up until line 5, where it fails. The object's prototype constructor is an array, however the object is no longer a true array. Your function returns true, but should return false.

Sorry my friend, no Jolt for you.

Search

Wowsers! A Tag Cloud!

Links

MiscLinks