web-dev-qa-db-ja.com

JS:Array.forEachを使用してgetElementsByClassNameの結果を反復処理する

私はいくつかのDOM要素を繰り返したいのですが、私はこれをやっています:

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

しかし、エラーが発生します:document.getElementsByClassName( "myclass")。forEachは関数ではありません

Firefox 3を使用しているので、getElementsByClassNameArray.forEachの両方が存在することがわかります。これはうまくいきます:

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

getElementsByClassNameの結果は配列ですか?そうでない場合、それは何ですか?

175
Steve Claridge

いいえ。 DOM4で指定 のように、 HTMLCollection です(少なくとも最新のブラウザでは、古いブラウザは NodeList を返しました)。

最近のすべてのブラウザー(他のほとんどIE <= 8)では、配列の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);
});
283
Tim Down

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を持つコレクションを返しますが、mapfilterのような他のメソッドが欠落しているため、この構文は依然として有用です:

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

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

または NodeListを返すquerySelectorAllを使用できます

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

最新のブラウザー(Edgeを含むがIEを除く)でサポート:
querySelectorAllを使用できます
NodeList.prototype.forEach()

MDN:Document.querySelectorAll()

15
icl7126

編集: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>

これは、Win 7のIE 9、FF 5、Safari 5、およびChrome 12で機能します。

14
james.garriss

GetElementsByClassNameの結果は配列ですか?

いや

そうでない場合、それは何ですか?

複数の要素を返すすべてのDOMメソッドと同様に、それはNodeListです。 https://developer.mozilla.org/en/DOM/document.getElementsByClassName を参照してください

5
Quentin

getElementsByClassName()の結果は配列ではなく、配列のようなオブジェクトです。具体的には、HTMLCollectionと呼ばれます。NodeListと混同しないでください( 独自のforEach()メソッドがあります )。

ES2015で、まだ言及されていないArray.prototype.forEach()で使用するために配列のようなオブジェクトを変換する簡単な方法の1つは、スプレッド演算子または スプレッド構文 を使用することです:

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

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

既に述べたように、getElementsByClassNameHTMLCollection を返します。

[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を反復可能として定義するようになったため、違いは重要です。

Web IDL draftによると、

反復可能と宣言されたインターフェースを実装するオブジェクトは、値のシーケンスを取得するために反復されることをサポートします。

:ECMAScript言語バインディングでは、反復可能なインターフェイスには「エントリ」、「forEach」、「キー」、「値」、および- @@ iterator そのプロパティ インターフェイスプロトタイプオブジェクト

つまり、forEachを使用する場合は、 querySelectorAll のようなNodeListを返すDOMメソッドを使用できます。

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

これはまだ広くサポートされていないことに注意してください。 Node.childNodesのforEachメソッド? も参照してください。

3
Oriol

Arrayを返すのではなく、 NodeList を返します。

0
reko_t

これはより安全な方法です。

var elements = document.getElementsByClassName("myclass");
for (var i = 0; i < elements.length; i++) myFunction(elements[i]);
0
gildniy

getElementsByClassNameは、最新のブラウザーではHTMLCollectionを返します。

これは引数に似た配列のようなオブジェクトであり、これはfor...ofループによって反復可能です MDN docがそれについて言っていることを参照してください:

for ... ofステートメントは、反復可能なオブジェクトを反復処理するループを作成します組み込みのString、Array、Array-likeオブジェクト(例、引数またはNodeList)、TypedArray、Map、Set、およびユーザー定義のイテラブル。オブジェクトの個別のプロパティの値に対して実行されるステートメントを使用して、カスタム反復フックを呼び出します。

for (let element of getElementsByClassName("classname")){
   element.style.display="none";
}
0
Haritsinh Gohil