変更するための短いスクリプトを作成していました<abbr>
要素の内部テキストですが、nodelist
にはforEach
メソッドがないことがわかりました。 nodelist
はArray
から継承しないことを知っていますが、forEach
が便利なメソッドのように思えませんか? forEach
をnodelist
に追加することを妨げる特定の実装の問題はありますか?
注:DojoとjQueryの両方に、ノードリスト用の何らかの形式で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標準から削除された でした。少なくとも現時点では、さまざまな技術的および仕様に関連する理由でまだ実装が不可能でした。
できるよ
Array.prototype.forEach.call (nodeList, function (node) {
// Your code here.
} );
ノードの新しい配列を作成することを検討できます。
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
決して言わないでください。2016年であり、NodeList
オブジェクトは最新のchrome(v52.0.2743.116)でforEach
メソッドを実装しています。
他のブラウザではまだサポートされていないため(FF 49でテスト済み)、本番環境で使用するのは時期尚早ですが、すぐに標準化されると思います。
要するに、そのメソッドを実装するための設計の矛盾です。
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?)
NodeListでforEachを使用する場合は、配列からその関数をコピーするだけです。
NodeList.prototype.forEach = Array.prototype.forEach;
以上で、Arrayの場合と同じ方法で使用できます。
document.querySelectorAll('td').forEach(function(o){
o.innerHTML = 'text';
});
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));
_
私の解決策:
//foreach for nodeList
NodeList.prototype.forEach = Array.prototype.forEach;
//foreach for HTML collection(getElementsByClassName etc.)
HTMLCollection.prototype.forEach = Array.prototype.forEach;
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
});