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.
});