18

Something nice with plain javascript would be to be able to use forEach, map, filter, etc, on the items returned by document.querySelectorAll, document.getElementsBy* etc.

This'd lead to less dependency on jQuery, and simply cleaner code. Right now, this is how we can do it, in an ugly way:

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

This is... verbose.

Any way to be able to use forEach and the likes right away on the elements returned?

4

4 回答 4

14

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.

于 2012-12-19T17:00:00.073 回答
6
function forEach( a, fn ) {
    return [].forEach.call(a, fn);
};

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

还有很多:

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

也许你会需要

[].slice.call(a)

在某些情况下。

function forEach(a, fn) {
    return [].forEach.call([].slice.call(a), fn);
}
于 2012-12-19T18:43:41.603 回答
2

如果您不喜欢更改原型并希望所有数组函数都能正常工作,那么将您的集合转换为数组可能会更容易:

Array.from(document.querySelectorAll('a'))

所有数组函数都将可用,当新版本的 JavaScript 发布时无需更新代码:

Array.from(document.querySelectorAll('a')).forEach(a => console.log(a))
于 2016-06-21T10:08:02.630 回答
0

forEach现在可以直接使用而无需转换

https://developer.mozilla.org/en-US/docs/Web/API/NodeList

于 2019-03-11T22:26:32.753 回答