ShiftEleven

Array-like Objects in JavaScript

It may look like an Array. Hell, it even has a length attribute! However, it may not actually be an Array. JavaScript is sometimes a quirky language to say the least and the notion of what is an Array is no exception.

So what are these array-like objects that I speak of? Well there are a few of them, one of which is arguments. arguments is a special variable that is available inside the body of every function. It is in fact, the list of arguments that were passed in.

arguments

If you inspect the arguments variable in a tool such as Firebug, you will notice that it prints out like an array. It has elements in sequential order and it even has a length property.

var testFunction = function() {
  console.log(arguments);
  console.log(arguments.length);
};

So what am I griping about? Try doing arguments.shift(). Uh-oh, looks like arguments.shift isn't a function; but that's a function of an Array. Another bit of fun you can do is console.log(arguments.constructor). That will print to your console "Object()" while if you did [].constructor, that will print "Array()". Having fun yet?

This also isn't just limited to arguments. It seems that a lot of the DOM collections are returned as these objects rather than arrays: document.getElementsByTagName(), document.images, document.childNodes. In some cases, these array-not-arrays would be better suited to become arrays.

Making the Array-like Objects become Arrays

Well, that heading is a misnomer. If we want those array-like objects to behave like arrays, we are going to need a new array.

var testFunction = function() {
  // Create a new array from the contents of arguments
  var args = Array.prototype.slice.call(arguments);

  var a = args.shift();
  console.log("The first argument is: %s", a);

  // send the remaining arguments to some other function
  someOtherFunction(args);
};

Clearly, the magic is all in Array.prototype.slice.call(arguments). So let me break it down per piece.

Array
this is the name of the base object that we want
prototype
this can be thought of as the namespace for the instance methods of an array
slice
this extracts a section of an array and returns a new array, and without a beginning and ending index, it simply returns a copy of the array
call
this is a very useful function, it allows you to call a function from one object and use it in the context of another

Tada! As a side note, if you are used to using the prototype framework, then you can convert these array-like objects to arrays using $A(), even though Prototype does it's array conversion differently.

Speaking of $A. Let's say you don't like typing that long string code above and you're not using Prototype. Then you can create a shortcut just like the Prototype folks:

var $A = function(obj) {
  return Array.prototype.slice.call(obj);
};

// Example usage:
$A(document.getElementsByTagName("li"));

Comments

comments powered by Disqus