web-dev-qa-db-ja.com

nodelistにforEachがないのはなぜですか?

変更するための短いスクリプトを作成していました<abbr>要素の内部テキストですが、nodelistにはforEachメソッドがないことがわかりました。 nodelistArrayから継承しないことを知っていますが、forEachが便利なメソッドのように思えませんか? forEachnodelistに追加することを妨げる特定の実装の問題はありますか?

注:DojoとjQueryの両方に、ノードリスト用の何らかの形式でforEachがあることを認識しています。制限のためどちらも使用できません。

84

NodeListはすべての主要なブラウザーでforEach()を使用するようになりました

MDN上のnodeList forEach() を参照してください。

元の答え

これらの答えはいずれも説明しませんwhyNodeListはArrayを継承しないため、forEachおよびその他すべてを許可します。

答えが見つかりました このes-discussスレッド上 。要するに、それはウェブを壊します:

問題は、instanceofがArray.prototype.concatと組み合わせた配列であることを意味する、instanceofを誤って想定したコードでした。

Googleのクロージャーライブラリにバグがあり、これが原因でほとんどすべてのGoogleのアプリが失敗しました。ライブラリはこれが発見されるとすぐに更新されましたが、concatと組み合わせて同じ誤った仮定を行うコードがまだ残っている可能性があります。

つまり、いくつかのコードは次のようなことをしました

if (x instanceof Array) {
  otherArray.concat(x);
} else {
  doSomethingElseWith(x);
}

ただし、concatは、「実際の」配列(Arrayのインスタンスではない)を他のオブジェクトとは異なる方法で処理します。

[1, 2, 3].concat([4, 5, 6]) // [1, 2, 3, 4, 5, 6]
[1, 2, 3].concat(4) // [1, 2, 3, 4]

つまり、上記のコードはxがNodeListであるときに壊れたためです。doSomethingElseWith(x)パスを進む前に、その後otherArray.concat(x)パスをたどって何かをしたためですxが実際の配列ではないため、奇妙です。

しばらくの間、Arrayの実際のサブクラスであり、「新しいNodeList」として使用されるElementsクラスの提案がありました。しかし、それは DOM標準から削除された でした。少なくとも現時点では、さまざまな技術的および仕様に関連する理由でまだ実装が不可能でした。

85
Domenic

できるよ

Array.prototype.forEach.call (nodeList, function (node) {

    // Your code here.

} );
53
akuhn

ノードの新しい配列を作成することを検討できます。

  var nodeList = document.getElementsByTagName('div'),

      nodes = Array.prototype.slice.call(nodeList,0); 

  // nodes is an array now.
  nodes.forEach(function(node){ 

       // do your stuff here.  

  });

注:これは、ここで作成するノード参照のリスト/配列であり、重複ノードはありません。

  nodes[0] === nodeList[0] // will be true
32
sbr

決して言わないでください。2016年であり、NodeListオブジェクトは最新のchrome(v52.0.2743.116)でforEachメソッドを実装しています。

他のブラウザではまだサポートされていないため(FF 49でテスト済み)、本番環境で使用するのは時期尚早ですが、すぐに標準化されると思います。

18
maioman

要するに、そのメソッドを実装するための設計の矛盾です。

MDNから:

NodeListでforEachまたはmapを使用できないのはなぜですか?

NodeListは配列と非常によく使用され、それらに対してArray.prototypeメソッドを使用するのは魅力的です。ただし、これは不可能です。

JavaScriptには、プロトタイプに基づいた継承メカニズムがあります。プロトタイプチェーンは次のように見えるため、配列インスタンスは配列メソッド(forEachやmapなど)を継承します。

myArray --> Array.prototype --> Object.prototype --> null(オブジェクトのプロトタイプチェーンは、Object.getPrototypeOfを複数回呼び出すことで取得できます)

forEach、mapなどは、Array.prototypeオブジェクトの独自のプロパティです。

配列とは異なり、NodeListプロトタイプチェーンは次のようになります。

myNodeList --> NodeList.prototype --> Object.prototype --> null

NodeList.prototypeにはitemメソッドが含まれていますが、Array.prototypeメソッドは含まれていないため、NodeListでは使用できません。

ソース: https://developer.mozilla.org/en-US/docs/DOM/NodeListまでスクロールダウンして、なぜforEachまたはmapを使用できないのかNodeList?

16
Matt Lo

NodeListでforEachを使用する場合は、配列からその関数をコピーするだけです。

NodeList.prototype.forEach = Array.prototype.forEach;

以上で、Arrayの場合と同じ方法で使用できます。

document.querySelectorAll('td').forEach(function(o){
   o.innerHTML = 'text';
});
13
AlexTR

ES2015では、forEachメソッドをnodeListに使用できるようになりました。

_document.querySelectorAll('abbr').forEach( el => console.log(el));
_

MDNリンク を参照してください

ただし、es2015でHTMLコレクションまたはその他の配列のようなオブジェクトを使用する場合は、Array.from()メソッドを使用できます。このメソッドは、配列のようなオブジェクトまたは反復可能なオブジェクト(nodeList、HTMLコレクション、文字列などを含む)を取り、新しいArrayインスタンスを返します。次のように使用できます。

_const elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( el => console.log(el));
_

Array.from()メソッドはシム可能なので、次のようなes5コードで使用できます

_var elements = document.getElementsByTagName('abbr');
Array.from(elements).forEach( function(el) {
    console.log(el);
});
_

詳細については、 [〜#〜] mdn [〜#〜] ページを参照してください。

現在のブラウザーサポート を確認するには。

[〜#〜] or [〜#〜]

もう1つのes2015の方法は、スプレッド演算子を使用することです。

_[...document.querySelectorAll('abbr')].forEach( el => console.log(el));
_

MDNスプレッド演算子

スプレッドオペレーター-ブラウザーサポート

5

私の解決策:

//foreach for nodeList
NodeList.prototype.forEach = Array.prototype.forEach;
//foreach for HTML collection(getElementsByClassName etc.)
HTMLCollection.prototype.forEach = Array.prototype.forEach;
2
Bakos Bence

NodeListはDOM APIの一部です。 JavaScriptにも適用されるECMAScriptバインディングを見てください。 http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html 。 nodeListと、読み取り専用の長さプロパティと、ノードを返すitem(index)関数。

答えは、反復する必要があるということです。代替手段はありません。 Foreachは機能しません。私はJava DOM APIバインディングを使用していますが、同じ問題があります。

NodeList.forEach 仕様のMDNを確認します。

NodeList.forEach(function(item, index, nodeList) {
    // code block here
});

IEでは、 akuhn's answer を使用します。

[].forEach.call(NodeList, function(item, index, array) {
    // code block here
});
0
VesperX