A collection is not an array
I’m occassionally irked by the fact that a collection of DOM elements (more formally called a NodeList
) can’t be manipulated like an array, because it isn’t one. However it does look like one, and thinking it is one is a mistake made so often by JavaScript novices that for our upcoming JavaScript Reference I felt it necessary to note this point for every single DOM object that is, or returns, a collection.
You can iterate through a collection like an array:
for(var i=0; i<collection.length; i++)
{
//whatever
}
But you can’t use Array
methods like push()
, splice()
or reverse()
to manipulate it.
Except that you can, if you take the next step and convert it into an array. This is in fact trivial:
function collectionToArray(collection)
{
var ary = [];
for(var i=0, len = collection.length; i < len; i++)
{
ary.push(collection[i]);
}
return ary;
}
The code above is fully cross-browser, and is called with the original collection as an argument:
var elements = collectionToArray(document.getElementsByTagName('*'));
However if you only need to deal with browsers that support native object prototyping (Opera, Firefox and Safari 3) then you can simply create a toArray()
method of NodeList
:
NodeList.prototype.toArray = function()
{
var ary = [];
for(var i=0, len = this.length; i < len; i++)
{
ary.push(this[i]);
}
return ary;
};
Which can then be called as a method of the individual collection:
var elements = document.getElementsByTagName('*').toArray();
There is one obvious disadvantage to this conversion (however it’s done), which is that the resulting array will no longer be a NodeList
. Obvious, yes, but relevant because it has two implications:
- It will lose the properties and methods it inherited from
NodeList
. HoweverNodeList
only has one property (itslength
, which is also available for an array), and one method (theitem()
method, which is usually redundent anyway, since members can still be referred to with square-bracket notation). So this loss is not at all significant - It will no longer be a live collection. A
NodeList
is a reference to a collection of objects, and if that collection changes (for example, elements are added or removed) theNodeList
will automatically update to reflect that change; conversely our array is a static snapshot of the collection at one point in time, and so won’t update in response to changes in the DOM. Depending on your application, that could be significant.