Подтвердить что ты не робот

Как получить forEach, доступный на псевдо-массивах, возвращаемых querySelectorAll?

Что-то приятное с простым javascript будет иметь возможность использовать forEach, map, filter и т.д. для элементов, возвращаемых document.querySelectorAll, document.getElementsBy* и т.д.

Это привело к меньшей зависимости от jQuery и просто более чистого кода. Прямо сейчас, так мы можем сделать это, уродливо:

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

Это... подробный.

Любой способ иметь возможность использовать forEach и понравившихся сразу после возврата элементов?

4b9b3361

Ответ 1

Наивным способом было бы это сделать, если вы протестировали Chrome:

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

Это работает. На Webkit. Однако он не работает в Firefox. Поскольку FF возвращает HTMLCollection...

Самый кросс-браузерный способ, который я нашел:

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

Это не работает на IE8 и ниже, потому что они задыхаются при добавлении свойств в прототипы объектов хоста.

Полный список:

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;

Или, чтобы порадовать нашего дорогого Берги (а также потому, что он чище):

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

Учитывая связь с перфекционистами, в основном это не имеет никакого отношения. Проблема в том, что DOM в большинстве случаев не работает в браузерах при расширении. Эта модификация работоспособна во всех браузерах, за исключением IE <= 8.

Ответ 2

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

Ответ 3

Если вам не нравятся изменения прототипов и все функции массива просто работают, может быть проще просто преобразовать вашу коллекцию в массив:

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

Все функции массива будут доступны, нет необходимости обновлять код при выпуске новой версии JavaScript:

Array.from(document.querySelectorAll('a')).forEach(a => console.log(a))