childNodesをループします


83

私は次のようにchildNodesをループしようとしています:

var children = element.childNodes;
children.forEach(function(item){
    console.log(item);
});

ただし、機能上出力Uncaught TypeError: undefined is not a functionforEachます。私もchildren代わりに使用しようとしましたがchildNodes、何も変わりませんでした。

誰かが何が起こっているのか知っていますか?

回答:


121

変数childrenNodeListインスタンスであり、NodeListsは真Arrayではないため、forEachメソッドを継承しません。

また、一部のブラウザは実際にそれをサポートしています nodeList.forEach


ES5

slicefromArrayを使用しNodeListて、を適切なに変換できますArray

var array = Array.prototype.slice.call(children);

単に使用callforEachて、NodeListコンテキストとして呼び出して渡すこともできます。

[].forEach.call(children, function(child) {});


ES6

あなたは使用することができfrom、あなたを変換する方法をNodeListArray

var array = Array.from(children);

または、次のようなスプレッド構文を...使用することもできます

let array = [ ...children ];


使用できるハックはでNodeList.prototype.forEach = Array.prototype.forEachあり、毎回変換しなくforEachても、どのハックでも使用できますNodeList

NodeList.prototype.forEach = Array.prototype.forEach
var children = element.childNodes;
children.forEach(function(item){
    console.log(item);
});

優れた説明とそれを行う他の方法については、NodeLists、Arrays、NodeListsの変換、およびDOMの理解に関する包括的な詳細を参照してください。


NodeListを純粋な配列に変換するにはどうすればよいですか?
user3828771 2014

例で更新されましたが、私が投稿したリンクを読んで、すべてを説明しています:)
GillesC 2014

2
または、次のようにすることもできます。[].forEach.call(element.childNodes, child => console.log(child))
XåpplI'-I0llwlg'I- 2015年

2
さらにクールなes6の方法:let items = [ ...children ]それを配列に変換します
2016

2
配列メソッドをNodeListsに適用することには大きな落とし穴があります。node.childNodesなどのNodeListsはライブリストであり、ループ中にDOMを操作すると、NodeListが変更される可能性があります。つまり、forEach()へのコールバックは呼び出されません。リストのすべての要素(または元々リストにあった要素よりも多くの要素)は、予測できない結果につながります。NodeListをループする前に、NodeListを配列に変換することをお勧めします。
stephband 2016

30

私はパーティーに非常に遅れていますが、それ以来element.lastChild.nextSibling === null、以下は私にとって最も簡単なオプションのようです:

for(var child=element.firstChild; child!==null; child=child.nextSibling) {
    console.log(child);
}

1
最も簡単なオプションは、通常の「for」ループを使用することです。しかし、あなたの選択肢は興味深いものです。
キリルレズニコフ2016

私はこれが一番好きで、同じものを実装することを計画していました。論理的で変換を必要としない
Ujjwal Singh

23

これがfor-inループでそれを行う方法です。

var children = element.childNodes;

for(child in children){
    console.log(children[child]);
}

14
チェックを忘れました:if(children.hasOwnProperty(child)){//ここにコードを記述}または「長さ」などの不要な小道具を繰り返し処理します!
キリルレズニコフ2016

7
さらに良いこと:使用してくださいfor ... of ...、それはES6構文です。
Jespertheend

4

forループで試してください。これはforEachノードのコレクションであるため、エラーが発生しますnodelist

または、これはノードリストを配列に変換する必要があります

function toArray(obj) {
  var array = [];
  for (var i = 0; i < obj.length; i++) { 
    array[i] = obj[i];
  }
return array;
}

またはこれを使用できます

var array = Array.prototype.slice.call(obj);

4

を使用して、別のメソッドを追加することに抵抗できませんでしたchildElementCount。指定された親からの子要素ノードの数を返すため、ループすることができます。

for(var i=0, len = parent.childElementCount ; i < len; ++i){
    ... do something with parent.children[i]
    }


2

これを試してください[逆順トラバーサル]:

var childs = document.getElementById('parent').childNodes;
var len = childs.length;
if(len --) do {
    console.log('node: ', childs[len]);
} while(len --);

または[トラバーサル順]

var childs = document.getElementById('parent').childNodes;
var len = childs.length, i = -1;
if(++i < len) do {
    console.log('node: ', childs[i]);
} while(++i < len);

単純なforループは、whileループよりも読みやすくなっています。著者は、逆順/逆順の走査を要求しません。
キリルレズニコフ2016

2

これは、を反復処理する機能的なES6の方法ですNodeList。このメソッドは、次ArrayforEachように'を使用します。

Array.prototype.forEach.call(element.childNodes, f)

f子ノードを最初のパラメーターとして受け取り、インデックスを2番目のパラメーターとして受け取るイテレーター関数はどこにありますか。

NodeListを複数回繰り返す必要がある場合は、これから小さな機能ユーティリティメソッドを作成できます。

const forEach = f => x => Array.prototype.forEach.call(x, f);

// For example, to log all child nodes
forEach((item) => { console.log(item); })(element.childNodes)

// The functional forEach is handy as you can easily created curried functions
const logChildren = forEach((childNode) => { console.log(childNode); })
logChildren(elementA.childNodes)
logChildren(elementB.childNodes)

map()および他の配列関数に対して同じトリックを実行できます。)


0

この種のことをたくさん行う場合は、自分で関数を定義する価値があるかもしれません。

if (typeof NodeList.prototype.forEach == "undefined"){
    NodeList.prototype.forEach = function (cb){
        for (var i=0; i < this.length; i++) {
            var node = this[i];
            cb( node, i );
        }
    };
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.