JS: повторение результата getElementsByClassName с использованием массива Array.forEach
Я хочу перебрать некоторые элементы DOM, я делаю это:
document.getElementsByClassName( "myclass" ).forEach( function(element, index, array) {
//do stuff
});
но я получаю сообщение об ошибке: document.getElementsByClassName( "myclass" ). forEach не является функцией
Я использую Firefox 3, поэтому я знаю, что присутствуют как getElementsByClassName
, так и Array.forEach
. Это отлично работает:
[2, 5, 9].forEach( function(element, index, array) {
//do stuff
});
Является результатом getElementsByClassName
массива? Если нет, что это такое?
Ответы
Ответ 1
Нет. Как указано в DOM4, это HTMLCollection
(по крайней мере, в современных браузерах. Старые браузеры возвращали NodeList
).
Во всех современных браузерах (почти во всех других IE <= 8) вы можете вызывать метод Array forEach
, передавая ему список элементов (будь то HTMLCollection
или NodeList
) в качестве значения this
:
var els = document.getElementsByClassName("myclass");
Array.prototype.forEach.call(els, function(el) {
// Do stuff here
console.log(el.tagName);
});
// Or
[].forEach.call(els, function (el) {...});
Если вы счастливы использовать ES6 (то есть вы можете спокойно игнорировать Internet Explorer или использовать ES5-транспортер), вы можете использовать Array.from
:
Array.from(els).forEach((el) => {
// Do stuff here
console.log(el.tagName);
});
Ответ 2
Вы можете использовать Array.from
для преобразования коллекции в массив, который намного чище, чем Array.prototype.forEach.call
:
Array.from(document.getElementsByClassName("myclass")).forEach(
function(element, index, array) {
// do stuff
}
);
В старых браузерах, которые не поддерживают Array.from
, вам нужно использовать что-то вроде Babel.
ES6 также добавляет этот синтаксис:
[...document.getElementsByClassName("myclass")].forEach(
(element, index, array) => {
// do stuff
}
);
Деструктурирование rest с помощью ...
работает со всеми объектами, похожими на массивы, а не только с самими массивами, тогда для создания массива из значений используется старый добрый синтаксис массива.
Хотя альтернативная функция querySelectorAll
(которая делает getElementsByClassName
устаревшей) возвращает коллекцию, которая изначально имеет forEach
, другие методы, такие как map
или filter
, отсутствуют, поэтому этот синтаксис все еще полезен:
[...document.querySelectorAll(".myclass")].map(
(element, index, array) => {
// do stuff
}
);
[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);
Ответ 3
Или вы можете использовать querySelectorAll
, который возвращает NodeList :
document.querySelectorAll('.myclass').forEach(...)
Поддерживается современными браузерами (включая Edge, но не IE):
Могу ли я использовать querySelectorAll
NodeList.prototype.forEach()
MDN: Document.querySelectorAll()
Ответ 4
Изменить: хотя тип возвращаемого текста был изменен в новых версиях HTML (см. обновленный ответ Tim Down), код ниже все еще работает.
Как говорили другие, это NodeList. Вот полный рабочий пример, который вы можете попробовать:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
function findTheOddOnes()
{
var theOddOnes = document.getElementsByClassName("odd");
for(var i=0; i<theOddOnes.length; i++)
{
alert(theOddOnes[i].innerHTML);
}
}
</script>
</head>
<body>
<h1>getElementsByClassName Test</h1>
<p class="odd">This is an odd para.</p>
<p>This is an even para.</p>
<p class="odd">This one is also odd.</p>
<p>This one is not odd.</p>
<form>
<input type="button" value="Find the odd ones..." onclick="findTheOddOnes()">
</form>
</body>
</html>
Это работает в IE 9, FF 5, Safari 5 и Chrome 12 на Win 7.
Ответ 5
Результатом getElementsByClassName()
является не массив, а объект типа массива. В частности, он называется HTMLCollection
, его не следует путать с NodeList
(который имеет собственный метод forEach()
).
Один простой способ с ES2015 преобразовать подобный массиву объект для использования с Array.prototype.forEach()
который еще не был упомянут, состоит в том, чтобы использовать оператор распространения или синтаксис распространения:
const elementsArray = document.getElementsByClassName('myclass');
[...elementsArray].forEach((element, index, array) => {
// do something
});
Ответ 6
Является ли результат getElementsByClassName массивом?
Нет
Если нет, что это такое?
Как и все методы DOM, которые возвращают несколько элементов, это NodeList, см. https://developer.mozilla.org/en/DOM/document.getElementsByClassName
Ответ 7
Как уже говорилось, getElementsByClassName
возвращает HTMLCollection, который определяется как
[Exposed=Window]
interface HTMLCollection {
readonly attribute unsigned long length;
getter Element? item(unsigned long index);
getter Element? namedItem(DOMString name);
};
Раньше некоторые браузеры вместо NodeList возвращали некоторые браузеры.
[Exposed=Window]
interface NodeList {
getter Node? item(unsigned long index);
readonly attribute unsigned long length;
iterable<Node>;
};
Разница важна, поскольку DOM4 теперь определяет NodeLists как iterable.
В соответствии с Web IDL,
Объекты, реализующие интерфейс, объявленный как итерируемый поддержка повторяется для получения последовательности значений.
Примечание. В языковой привязке ECMAScript используется интерфейс, который iterable будет иметь "записи", "forEach", "keys", "values" и @@iterator свойства на объекте прототипа интерфейса.
Это означает, что если вы хотите использовать forEach
, вы можете использовать метод DOM, который возвращает NodeList, например querySelectorAll
.
document.querySelectorAll(".myclass").forEach(function(element, index, array) {
// do stuff
});
Обратите внимание, что это пока еще не поддерживается. Также см. для каждого метода Node.childNodes?
Ответ 8
Он не возвращает Array
, он возвращает NodeList.
Ответ 9
Это более безопасный способ:
var elements = document.getElementsByClassName("myclass");
for (var i = 0; i < elements.length; i++) myFunction(elements[i]);
Ответ 10
getElementsByClassName
возвращает HTMLCollection в современных браузерах.
который является массивоподобным объектом, похожим на аргументы, который можно перебрать с помощью цикла for...of
смотрите ниже, что MDN doc говорит об этом:
Оператор for... of создает цикл, повторяющийся над повторяемыми объектами, включая: встроенные объекты String, Array, Array-like (например, arguments или NodeList), TypedArray, Map, Set и определяемые пользователем итерируемые элементы. Он вызывает пользовательский итерационный хук с инструкциями, которые должны быть выполнены для значения каждого отдельного свойства объекта.
пример
for (let element of getElementsByClassName("classname")){
element.style.display="none";
}
Ответ 11
Вот тест, который я создал на jsperf:
https://jsperf.com/vanillajs-loop-through-elements-of-class
Самая популярная версия в Chrome и Firefox - это старый добрый цикл for в сочетании с document.getElementsByClassName:
var elements = document.getElementsByClassName('testClass'), elLength = elements.length;
for (var i = 0; i < elLength; i++) {
elements.item(i).textContent = 'Tested';
};
В Safari этот вариант является победителем:
var elements = document.querySelectorAll('.testClass');
elements.forEach((element) => {
element.textContent = 'Tested';
});
Если вам нужен наиболее удобный вариант для всех браузеров, он может быть следующим:
var elements = document.getElementsByClassName('testClass');
Array.from(elements).map(
(element) => {
return element.textContent = 'Tested';
}
);