JS: итерация по результату getElementsByClassName с использованием массива.инструкция foreach


Я хочу перебрать некоторые элементы DOM, я делаю это:

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

но я получаю сообщение об ошибке: документ.getElementsByClassName ("myclass").forEach-это не функция

Я использую Firefox 3, поэтому я знаю, что оба getElementsByClassName и Array.forEach присутствуют. Это прекрасно работает:

[2, 5, 9].forEach( function(element, index, array) {
  //do stuff
});

результат getElementsByClassName массив? Если нет, то что это?

8 138

8 ответов:

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

во всех современных браузерах (почти все другие IE 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) {...});

можно использовать Array.from преобразовать коллекцию в массив, который намного чище, чем Array.prototype.forEach.call:

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

в старых браузерах, которые не поддерживают Array.from, вам нужно использовать что-то вроде Вавилона.


ES6 также добавляет этот синтаксис:

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

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


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

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

[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);

Edit: хотя тип возврата изменился в новых версиях 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.

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

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

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

MDN:документ.querySelectorAll()

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

нет

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

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

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

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

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

[...elementsArray].forEach((element, index, array) => {
    // do something
});

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

[Exposed=Window]
interface HTMLCollection {
  readonly attribute unsigned long length;
  getter Element? item(unsigned long index);
  getter Element? namedItem(DOMString name);
};

ранее некоторые браузеры возвращали a 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", "ключи", "значения" и @@iterator свойства объект-прототип интерфейса.

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

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

обратите внимание, что это еще не получило широкой поддержки. Также смотрите метод forEach узла.childNodes?

Он не возвращает Array возвращает NodeList.