JS: перебирая результат getElementsByClassName, используя Array.forEach - PullRequest
184 голосов
/ 06 октября 2010

Я хочу перебрать некоторые элементы 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 массивом? Если нет, то что это?

Ответы [ 10 ]

296 голосов
/ 06 октября 2010

Нет. Как указано в DOM4 , это HTMLCollection (по крайней мере, в современных браузерах. Старые браузеры возвращали NodeList).

Во всех современных браузерах (почти во всех остальных IE <= 8) вы можете вызывать метод Array <code>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);
});
56 голосов
/ 21 июня 2016

Вы можете использовать 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
    }
);

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


В то время как альтернативная функция querySelectorAll (что делает getElementsByClassName устаревшей) возвращает коллекцию, которая имеет forEach изначально, другие методы, такие какmap или filter отсутствуют, поэтому этот синтаксис по-прежнему полезен:

[...document.querySelectorAll(".myclass")].map(
    (element, index, array) => {
        // do stuff
    }
);

[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);
15 голосов
/ 13 мая 2017

Или вы можете использовать querySelectorAll, который возвращает NodeList :

document.querySelectorAll('.myclass').forEach(...)

Поддерживается современными браузерами (включая Edge, но не IE):
Могу ли я использовать querySelectorAll
NodeList.prototype.forEach ()

MDN: Document.querySelectorAll ()

14 голосов
/ 29 июня 2011

Редактировать: Хотя тип возврата изменился в новых версиях HTML (см. Обновленный ответ Тима Дауна), приведенный ниже код по-прежнему работает.

Как уже говорили другие, это 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 голосов
/ 03 октября 2017

Результатом getElementsByClassName() является не массив, а массивоподобный объект . В частности, он называется HTMLCollection, его не следует путать с NodeList (, у которого есть собственный forEach() метод ).

Один простой способ с ES2015 преобразовать подобный массиву объект для использования с Array.prototype.forEach(), который еще не был упомянут, состоит в том, чтобы использовать оператор распространения или синтаксис распространения :

const elementsArray = document.getElementsByClassName('myclass');

[...elementsArray].forEach((element, index, array) => {
    // do something
});
5 голосов
/ 06 октября 2010

Является ли результат getElementsByClassName массивом?

Нет

Если нет, то что это?

Каксо всеми методами DOM, которые возвращают несколько элементов, это NodeList, см. https://developer.mozilla.org/en/DOM/document.getElementsByClassName

3 голосов
/ 23 апреля 2016

Как уже сказано, getElementsByClassName возвращает HTMLCollection , который определяется как

[Exposed=Window]
interface <i>HTMLCollection</i> {
  readonly attribute unsigned long <a href="https://www.w3.org/TR/dom/#dom-htmlcollection-length" rel="nofollow noreferrer">length</a>;
  getter <a href="https://www.w3.org/TR/dom/#element" rel="nofollow noreferrer">Element</a>? <a href="https://www.w3.org/TR/dom/#dom-htmlcollection-item" rel="nofollow noreferrer">item</a>(unsigned long <i>index</i>);
  getter <a href="https://www.w3.org/TR/dom/#element" rel="nofollow noreferrer">Element</a>? <a href="https://www.w3.org/TR/dom/#dom-htmlcollection-nameditem" rel="nofollow noreferrer">namedItem</a>(DOMString <i>name</i>);
};

Ранее некоторые браузеры возвращали NodeList .

[Exposed=Window]
interface <i>NodeList</i> {
  getter <a href="https://www.w3.org/TR/dom/#node" rel="nofollow noreferrer">Node</a>? <a href="https://www.w3.org/TR/dom/#dom-nodelist-item" rel="nofollow noreferrer">item</a>(unsigned long <i>index</i>);
  readonly attribute unsigned long <a href="https://www.w3.org/TR/dom/#dom-nodelist-length" rel="nofollow noreferrer">length</a>;
  iterable<<a href="https://www.w3.org/TR/dom/#node" rel="nofollow noreferrer">Node</a>>;
};

Разница важна, поскольку DOM4 теперь определяет NodeList s как итеративный.

Согласно Web IDL черновик,

Объекты, реализующие интерфейс, который объявлен как итеративный поддержка итерации для получения последовательности значений.

Примечание : В привязке языка ECMAScript интерфейс, который итерируемый будет иметь «записи», «forEach», «ключи», «значения» и @@ iterator свойств своего прототипа объекта интерфейса .

Это означает, что, если вы хотите использовать forEach, вы можете использовать метод DOM, который возвращает NodeList , например querySelectorAll.

document.querySelectorAll(".myclass").forEach(function(element, index, array) {
  // do stuff
});

Обратите внимание, что пока это широко не поддерживается. Также см. forEach метод Node.childNodes?

0 голосов
/ 03 июля 2019

getElementsByClassName возвращает HTMLCollection в современных браузерах.

что массивоподобный объект, похожий на аргументы , который можно повторять в цикле for...of, смотрите ниже, что MDN документ говорит об этом:

Оператор for ... создает цикл, повторяющийся над повторяемыми объектами , включая: встроенные String, Array, объекты, подобные массиву (например, аргументы или NodeList), TypedArray, Map, Set и определяемые пользователем итерации. Это вызывает пользовательский итерационный хук с инструкциями, которые должны быть выполнены для значение каждого отдельного свойства объекта.

пример

for (let element of getElementsByClassName("classname")){
   element.style.display="none";
}
0 голосов
/ 22 июня 2019

Это более безопасный способ:

var elements = document.getElementsByClassName("myclass");
for (var i = 0; i < elements.length; i++) myFunction(elements[i]);
0 голосов
/ 06 октября 2010

Не возвращает Array, возвращается NodeList .

...