Go back to home page of Unsolicited Advice from Tiffany B. Brown

Iterating and applying functions to NodeLists with map() and forEach

Yesterday, I wrote about two methods of the JavaScript Array object: map() and forEach().

Typically, you'd invoke these methods on an array, for example [1,2,3].map( function(n){ return n*2; }). But what if you want to invoke a function for a group of items that isn't an array — a NodeList for example?

You could convert it to an array of objects, as shown below.

var nodelist = document.getElementsByTagName('p'),
    len = nodelist.length,
    arrayofnodes = [],
    i;

    for(i = 0; i < len; i++){
        arrayofnodes[i] = nodelist[i];
    }

    arrayofnodes.map( function(n){ /* do something */ })

It's possible, however, to use map() and forEach() on array-like objects such as NodeList by using the call() method of the Function object. Remember, all methods are also function objects so the Function methods can be used here too.

A quick overview of call()

Now what now? Yeah, I know. ECMAScript has a few different ways to invoke a function or method, one of which is by using the call() method to, uh, call a method.

function sayit(thingtosay){
    console.log(thingtosay);
}
sayit('Go tell it on the mountain.');
sayit.call(null, 'Over the hills and everywhere!'); // Writes second parameter to the console.

The call() method accepts multiple arguments, the first of which is the object on which to act, if there is one. Additional arguments become passed to the function you're trying to invoke.

In the case of a NodeList, we could use call() to invoke the map() (or forEach()) method and trick it into treating it like an array.

var nodelist = document.getElementsByTagName('p');
Array.prototype.map.call( nodelist, function(n){
    console.log( n.innerHTML ); // writes the innerHTML of every p element.
});