getElementsByClassNameからの配列に対してforEachを使用すると、「TypeError:undefined is not a function」という結果になります


91

では私のJSFiddle、私は単に要素の配列を反復処理しようとしています。ログステートメントが証明するように、配列は空ではありません。しかし、への呼び出しforEachにより、(あまり役立たない)「キャッチされていませんTypeErrorundefined関数ではありません」というエラーが表示されます。

私は愚かなことをしているに違いない。私は何を間違っていますか?

私のコード:

var arr = document.getElementsByClassName('myClass');
console.log(arr);
console.log(arr[0]);
arr.forEach(function(v, i, a) {
  console.log(v);
});
.myClass {
  background-color: #FF0000;
}
<div class="myClass">Hello</div>


8
arrは配列ではなく、HTMLCollectionです。配列と同じメソッドはありません。developer.mozilla.org/en-US/docs/Web/API/…。ここではそれについてのSOポストもあります:stackoverflow.com/questions/13433799/...は
イアン・

のようなもの[1,2,3].forEach(function(v,i,a) { console.log(v); });で結構です。これと私の例の配列の違いは何ですか?
Jer

あなたの例には配列がありません。配列だと思うのはなぜですか?
2014年

3
@Jer:arr instanceof Array結果として、Array.prototype.forEach()などfalseArrayオブジェクトのプロトタイプメソッドを利用できません。あるHTMLCollectionオブジェクトのような配列(ただし、継承またはインスタンス化しません)。したがって、標準ループは、オブジェクトのインデックスを単に反復するだけで機能し、のプロトタイプではありません。arrArrayforArray
いいえ、2014年

1
@Jer —組み込みオブジェクトとホストオブジェクトの違いを調べる必要があります。前者はECMA-262に準拠し、後者はホストが望むだけです。DOMには、主にNodeListインターフェースに基づいた、インデックス(document.images、document.forms、form.elements、select.optionsなど)によるメンバーへのアクセスを可能にする多くのオブジェクトがあります
RobG 2014年

回答:


162

これは、配列ではなくHTMLCollectionをdocument.getElementsByClassName返すため です。

幸いなことに、これは「配列のような」オブジェクトでありオブジェクトであるかのようにログに記録される理由と、標準forループで反復できる理由を説明します)、これを行うことができます。

[].forEach.call(document.getElementsByClassName('myClass'), function(v,i,a) {

ES6(最新のブラウザーまたはBabelを使用)では、Array.from配列のようなオブジェクトから配列を構築する次の方法も使用できます。

Array.from(document.getElementsByClassName('myClass')).forEach(v=>{

または、配列のようなオブジェクトを配列に展開します。

[...document.getElementsByClassName('myClass'))].forEach(v=>{

2
@Jer argumentsは1つです。jQueryオブジェクトは別のものです。自分で作成することもできます:var a = {"0": "str1", "1": "str2", length: 2}
Ian

1
ここで再び古いブラウザーを使用します。ホストオブジェクトをネイティブメソッドに渡すと、IE 8以下では失敗します。誰も気にしないかもしれませんが、気にする人もいます。;-)ああ、それはgetElementsByClassNameもサポートしていませんが、動作するquerySelectorAll('.myClass')はずです。イテレータがNodeList APIに追加されるのをまだ待っています。:-(
RobG 2014年

2
@Jer:なんらかの理由でループから抜け出すつもりである場合の補足として、そうするArray.prototype.forEachことはできません。後で標準forループを使用する必要がある場合、Array.prototype.everyまたは配列オブジェクトを使用する場合Array.prototype.some(またはすべてまたは一部がIE8以下ではサポートされていないことに注意してください)
Nope

1
@Ianオブジェクトを「配列のよう」にするには、スプライスが必要です。ここでログを比較します:jsbin.com/sigut/1/edit
DenysSéguretJun

1
@Ian TBH "配列のような"の定義は非常にあいまいであり、使用方法に依存します。時々私は含まれていませんsplice、その定義ではなく、私はより多くの「アレイ状」にしたいときに使用できるようにするにはmapfilterなど、その後、私はそれを含めます。を使用forEachした単純な反復は必要ありませんsplice
DenysSéguret2014年

11

これはうまくいくはずです:

<html>
  <head>
    <style type="text/css">
    </style>
  </head>
  <body>
   <div class="myClass">Hello</div>
   <div class="myClass">Hello</div>

<script type="text/javascript">
    var arr = document.getElementsByClassName('myClass');
    console.log(arr);
    console.log(arr[0]);
    arr = [].slice.call(arr); //I have converted the HTML Collection an array
    arr.forEach(function(v,i,a) {
        console.log(v);
    });
</script>


<style type="text/css">
    .myClass {
    background-color: #FF0000;
}
</style>

  </body>
</html>

0

特定のクラスの各要素のIDにアクセスする場合は、次の操作を実行できます。

    Array.from(document.getElementsByClassName('myClass')).forEach(function(element) {
        console.log(element.id);
    });
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.