In short, its a design conflict to implement that method.
From MDN:
Why can't I use forEach or map on a NodeList?
NodeList are used very much like arrays and it would be tempting to
use Array.prototype methods on them. This is, however, impossible.
JavaScript has an inheritance mechanism based on prototypes. Array
instances inherit array methods (such as forEach or map) because their
prototype chain looks like the following:
myArray --> Array.prototype --> Object.prototype --> null (the
prototype chain of an object can be obtained by calling several times
Object.getPrototypeOf)
forEach, map and the likes are own properties of the Array.prototype
object.
Unlike arrays, NodeList prototype chain looks like the following:
NodeList is part of the DOM API. Look at the ECMAScript bindings which apply to JavaScript as well. http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html. The nodeList and a read-only length property and item(index) function to return a node.
The answer is, you have to iterate. There is no alternative. Foreach will not work.
I work with Java DOM API bindings and have the same problem.
var nodeList = document.getElementsByTagName('div'),
nodes = Array.prototype.slice.call(nodeList,0);
// nodes is an array now.
nodes.forEach(function(node){
// do your stuff here.
});
Note: This is just a list/array of node references we are creating here, no duplicate nodes.
The problem was code that incorrectly assumed instanceof to mean that the instance was an Array in combination with Array.prototype.concat.
There was a bug in Google's Closure Library which caused almost all Google's apps to fail due to this. The library was updated as soon as this was found but there might still be code out there that makes the same incorrect assumption in combination with concat.
so that means that the above code broke when x was a NodeList, because before it went down the doSomethingElseWith(x) path, whereas afterward it went down the otherArray.concat(x) path, which did something weird since x wasn't a real array.
For some time there was a proposal for an Elements class that was a real subclass of Array, and would be used as "the new NodeList". However, that was removed from the DOM Standard, at least for now, since it wasn't feasible to implement yet for a variety of technical and specification-related reasons.
//foreach for nodeList
NodeList.prototype.forEach = Array.prototype.forEach;
//foreach for HTML collection(getElementsByClassName etc.)
HTMLCollection.prototype.forEach = Array.prototype.forEach;
However if you want to use HTML Collections or other array-like objects, in es2015, you can use Array.from() method. This method takes an array-like or iterable object (including nodeList, HTML Collections, strings etc) and returns a new Array instance. You can use it like this:
const elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( el => console.log(el));
As Array.from() method is shimmable, you can use it in es5 code like this
var elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( function(el) {
console.log(el);
});