How to have forEach available on pseudo-arrays returned by querySelectorAll?

A naive way would be to do this if you tested on Chrome:

NodeList.prototype.forEach = Array.prototype.forEach;

This works. On Webkit. It doesn't on Firefox though. Because FF returns an HTMLCollection...

The most cross-browser way I've found:

NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;

It doesn't work on IE8 and lower though, because they choke when adding properties to host objects prototypes.

Full list:

NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;
NodeList.prototype.map = HTMLCollection.prototype.map = Array.prototype.map;
NodeList.prototype.filter = HTMLCollection.prototype.filter = Array.prototype.filter;
NodeList.prototype.reduce = HTMLCollection.prototype.reduce = Array.prototype.reduce;
NodeList.prototype.reduceRight = HTMLCollection.prototype.reduceRight = Array.prototype.reduceRight;
NodeList.prototype.every = HTMLCollection.prototype.every = Array.prototype.every;
NodeList.prototype.some = HTMLCollection.prototype.some = Array.prototype.some;

Or, to please our dear Bergi (and also because it is cleaner):

['forEach', 'map', 'filter', 'reduce', 'reduceRight', 'every', 'some'].forEach(
    function(p) {
    NodeList.prototype[p] = HTMLCollection.prototype[p] = Array.prototype[p];
});

Considering the link to perfectionkills, it's mostly irrelevant there. The problem is that the DOM is mostly not behaving the same on browsers when extended. This modification is sane in all the browsers except IE <=8.


function forEach( a, fn ) {
    return [].forEach.call(a, fn);
};

forEach(document.querySelectorAll(sel), function(el) {
});

And many more:

function map( a, fn ) {
    return [].map.call(a, fn);
};
function filter( a, fn ) {
    return [].filter.call(a, fn);
};
function reduce( a, fn ) {
    return [].reduce.call(a, fn);
};
function reduceRight( a, fn ) {
    return [].reduceRight.call(a, fn);
};
function every( a, fn ) {
    return [].every.call(a, fn);
};
function some( a, fn ) {
    return [].some.call(a, fn);
};

Maybe you will need

[].slice.call(a)

in some situations.

function forEach(a, fn) {
    return [].forEach.call([].slice.call(a), fn);
}

Tags:

Javascript

Dom