web-dev-qa-db-ja.com

JavaScriptの一連の要素をループする最良の方法は何ですか?

過去および現在のほとんどのプロジェクトでは、次のようなforループを使用する傾向があります。

var elements = document.getElementsByTagName('div');
for (var i=0; i<elements.length; i++) {
    doSomething(elements[i]);
}

「reverse while」ループを使用する方が速いと聞きましたが、これを確認する本当の方法はありません。

var elements = document.getElementsByTagName('div'), 
    length = elements.length;

while(length--) {
    doSomething(elements[length]);
}

JavaScriptの要素、またはそれに関する配列をループ処理する場合、ベストプラクティスと見なされるものは何ですか?

52
James

これは私がよく使うループの素敵な形です。 forステートメントから反復変数を作成し、長さプロパティをチェックする必要はありません。長さプロパティは、NodeListを反復処理するときに特にコストがかかる可能性があります。ただし、注意する必要があります、あなたは配列内のいずれかの値が「偽」である可能性がある場合は使用できません。実際には、nullを含まないオブジェクトの配列(NodeListなど)を反復処理するときにのみ使用します。しかし、私はその構文糖が大好きです。

var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];

for (var i=0, item; item = list[i]; i++) {
  // Look no need to do list[i] in the body of the loop
  console.log("Looping: index ", i, "item" + item);
}

これは、リストに['-1']プロパティがない限り、逆方向にループするためにも使用できることに注意してください。

var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];

for (var i = list.length - 1, item; item = list[i]; i--) {
  console.log("Looping: index ", i, "item", item);
}

ES6アップデート

for...of は名前を提供しますが、インデックスは提供しません。 ES6

for (let item of list) {
    console.log("Looping: index ", "Sorry!!!", "item" + item);
}
56
Juan Mendes

場合によっては、needで逆順でループすることに注意してください(ただし、i--も使用できます)。

たとえば、誰かが新しいgetElementsByClassName関数を使用して、特定のクラスの要素をループし、このクラスを変更したいと考えていました。彼は2つの要素のうち1つだけが変更されていることを発見しました(FF3で)。
これは、関数がライブNodeListを返すためです。このため、Domツリーの変更が反映されます。リストを逆順にたどることで、この問題を回避できました。

var menus = document.getElementsByClassName("style2");
for (var i = menus.length - 1; i >= 0; i--)
{
  menus[i].className = "style1";
}

インデックスの進行を増やす場合、インデックス1を要求すると、FFはDomを検査し、元のDomの2番目であるstyle2の最初のアイテムをスキップし、3番目の初期アイテムを返します!

27
PhiLho

怒られる危険性があるので、 jqueryprototype のようなJavaScriptヘルパーライブラリを取得します。これらはNiceメソッドのロジックをカプセル化します。両方とも.eachメソッド/イテレータを持っていますそれを行う-そして、彼らは両方ともそれをクロスブラウザ互換にするように努めています

編集:この回答は2008年に投稿されました。今日、はるかに優れた構造が存在します。この特定のケースは、.forEach

それはおそらく既知の宇宙で最も一般的なループ構造であり、逆ループが実際にあなたをいつでも救うとは思わないので(おそらく増分/デクリメントおよび各反復での比較)。

他の人が認識および読み取り可能なコードは間違いなく良いことです。

6
Adam Bellaire

以前にdocument.getElementsByClassName()で非常によく似た問題がありました。当時、ノードリストが何であるかは知りませんでした。

var elements = document.getElementsByTagName('div');
for (var i=0; i<elements.length; i++) {
    doSomething(elements[i]);
}

私の問題は、要素が配列になると予想していたことでしたが、そうではありませんでした。 Document.getElementsByTagName()が返すノードリストは反復可能ですが、array.prototypeメソッドを呼び出すことはできません。

canただし、次のようなノードリスト要素を配列に追加します。

var myElements = [];
for (var i=0; i<myNodeList.length; i++) {                               
    var element = myNodeList[i];
    myElements.Push(element);
};

その後、配列の要素で.innerHTMLや.styleなどを自由に呼び出すことができます。

6

私も簡単な方法を使用することをお勧めします(KISS!-)

-しかし、いくつかの最適化が見つかりました。つまり、配列の長さを複数回テストしません。

var elements = document.getElementsByTagName('div');
for (var i=0, im=elements.length; im>i; i++) {
    doSomething(elements[i]);
}
5
roenving

Andrew Hedgesのテストに関する私のコメントも参照してください...

単純な反復、導入した最適化、および逆のdo/whileを比較するテストを実行してみました。ここでは、配列内の要素がすべてのループでテストされました。

そして、残念なことに、私がテストした3つのブラウザーの結果は非常に異なっていましたが、最適化された単純な反復はすべて最速でした!-)

テスト:

500,000個の要素を持つ配列は、実際のテストの外側に構築され、反復ごとに特定の配列要素の値が明らかになります。

テストを10回実行します。

IE6:

結果:

シンプル:984,922,937,984,891,907,906,891,906,906

平均:923.40ミリ秒。

最適化:766,766,844,797,750,750,765,765,766,766

平均:773.50ミリ秒。

逆実行/時:3375,1328,1516,1344,1375,1406,1688,1344,1297,1265

平均:1593.80ミリ秒。 (特に厄介な結果に注意してください)

Opera 9.52:

結果:

シンプル:344,343,344,359,343,359,344,359,359,359

平均:351.30ミリ秒。

最適化:281,297,297,297,297,281,281,297,281,281

平均:289.00ミリ秒

逆do/while:391,407,391,391,500,407,407,406,406,406

平均:411.20ミリ秒。

FireFox 3.0.1:

結果:

シンプル:278,251,259,245,243,242,259,246,247,256

平均:252.60ミリ秒。

最適化済み:267,222,223,226,223,230,221,231,224,230

平均:229.70ミリ秒。

逆do/while:414,381,389,383,388,389,381,387,400,379

平均:389.10ミリ秒。

4
roenving

Juan Mendezによって提供されるループの形式は非常に便利で実用的です。少し変更して、false、null、ゼロ、空の文字列でも動作するようにしました。

var items = [
    true,
    false,
    null,
    0,
    ""
];

for(var i = 0, item; (item = items[i]) !== undefined; i++)
{
    console.log("Index: " + i + "; Value: " + item);
}
3
user4416767

私はあなたがそれを聞きたくないことを知っていますが、この場合、ベストプラクティスが最も読みやすいと思います。ここから月までループがカウントされない限り、パフォーマンスゲインは十分ではありません。

1
Georgi

私はこの質問が古いことを知っています-しかし、これは別の非常に簡単な解決策です...

var elements = Array.from(document.querySelectorAll("div"));

その後、標準の配列のように使用できます。

0
Dustin Halstead

読みやすいので、forループの方が好きです。長さから0へのループは、0から長へのループよりも効率的です。そして、あなたが言ったように、逆のwhileループを使うことはfoorループよりも効率的です。比較結果のあるページへのリンクはもうありませんが、ブラウザによって違いが異なることを覚えています。一部のブラウザでは、whileループが逆に2倍速くなりました。ただし、「小さな」配列をループしている場合は違いはありません。あなたの例の場合、要素の長さは「小さい」

0
Gene

2つの選択肢があると思います。 jQueryや同様のフレームワークなどのdom要素では、反復の良い方法を提供します。 2番目のアプローチはforループです。

0
David Robbins