JavaScript for…in vs for


461

for ... inとforループに大きな違いがあると思いますか?どのような種類の「for」を使用するのが好きですか、またその理由は何ですか。

連想配列の配列があるとしましょう:

var myArray = [{'key': 'value'}, {'key': 'value1'}];

だから私たちは反復することができます:

for (var i = 0; i < myArray.length; i++)

そして:

for (var i in myArray)

大きな違いはありません。パフォーマンスの問題はありますか?


13
JS 1.6以降、次のものもあることに注意してくださいmyArray.forEach(callback[, thisarg])
Benji XVI

14
@Benji array.forEachは実際にはES5にあります。
mikemaccana 2012年

2
以下のためのインループますが、条件が必要で、このようになります:if(myArray.hasOwnProperty(i)){true}
エリックHodonsky

6
['foo', 'bar', 'baz'].forEach(function(element, index, array){ console.log(element, index, array); }); IE8以外のほとんどすべての場所で使用しても問題ありません。これは、最もエレガントな構文です
Jon z

5
あり、for...of中の文のECMAScript 6は、たとえば、:for (let i of myArray) console.log(i);
Vitalii Fedorenko

回答:


548

選択は、どのイディオムが最もよく理解されているかに基づく必要があります。

配列は以下を使用して反復されます:

for (var i = 0; i < a.length; i++)
   //do stuff with a[i]

連想配列として使用されているオブジェクトは、以下を使用して反復されます。

for (var key in o)
  //do stuff with o[key]

地球を粉砕する理由がない限り、確立された使用パターンに固執してください。


38
これは、ifステートメントのフィルタリングで使用するのに適した方法であることを述べておく必要があります。オブジェクト「obj.hasOwnProperty(member)」には、イテレータから返されたメンバーが実際にオブジェクトのメンバーであるかどうかをチェックする便利なメソッドがあります。参照:javascript.crockford.com/code.html
DamirZekić

57
別の回答でコメントしたように、「for ... in」はすべての配列のプロパティとメソッドを反復するため、配列に対して正しく機能しません。したがって、「for ... in」は、オブジェクトプロパティを反復する場合にのみ使用する必要があります。それ以外の場合は、「for(i = 0; i <something; i ++)」を使用します
DenilsonSáMaia 2010

パフォーマンス上の理由から、IMOではfor、ループのたびにa.lengthを評価するのではなく、の前に配列の長さを評価することをお勧めします。
UpTheCreek 2012年

9
@UpTheCreek:配列が実際にHTMLDOMによって返されたものである場合、それは間違いなく真実ですが、かなりの違いが見られるようになるまでに、標準のJavaScript配列がどれほど大きくなければならないのでしょうか。個人的には、別のことをするのに必要であることが証明されるまで、コードをできるだけ単純にしておくでしょう。
AnthonyWJones 2012年

2
@Pichan あなたのforループ状態でi < lはなくi < a、という意味だと思います。
Max Nanasy 2013年

161

Douglas Crockfordは、このステートメントの使用を避けるために、JavaScript:良い部分(24ページ)で推奨していますfor in

を使用for inしてオブジェクトのプロパティ名をループする場合、結果は順序付けされません。さらに悪いことに、予期しない結果が生じる可能性があります。これには、プロトタイプチェーンから継承されたメンバーとメソッドの名前が含まれます。

プロパティ以外はすべて、を使用して除外できます.hasOwnProperty。このコードサンプルは、おそらく最初に必要なことを実行します。

for (var name in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, name)) {
        // DO STUFF
    }
}

70
for ... inは、オブジェクトプロパティのループ処理に完全に適しています。配列要素のループには適していません。これらのシナリオの違いを理解できない場合は、はい、避けてください... それ以外の場合、ナッツを行きます。
Shog9 2008年

8
注文されていないことを強調したい!これは大きな問題になる可能性があり、把握するのが難しいバグです。
Jason、

4
+1「プロトタイプチェーンから継承されたメンバーとメソッドの名前が含まれます。」たとえば、誰かがPrototypeをロードした状態でコードを使用した場合(コードが実際にコードを使用していなくても)は楽しいでしょう。
ijw 2009

13
することを忘れないでください宣言するname変数を:for(var name in object)...そのコードは、例えば関数内であれば、そうでない場合は、nameグローバルオブジェクト(への代入の財産であることまで変数終了宣言されていない識別子また新しいのECMAScriptで、ないもの) 5厳格モード、そのコードはをスローしReferenceErrorます。
CMS

6
@Nosredna:John Resig以外から提出されたChromeの反復順序に関する問題があり、WontFixとマークされています。code.google.com/p/chromium/issues/detail?id=883。Chromeの前でも、プロパティを削除してから再度追加した場合、反復の順序はブラウザ間で同じではありませんでした。また、IE 9はChromeとよく似た動作をします(おそらく速度向上のため)。だから...不正確な情報を広めるのをやめてください、あなたはそれに依存し続けるのは非常にナイーブです。
ファンメンデス、2011

62

FYI-jQueryユーザー


jQueryのeach(callback)メソッドはfor( ; ; )デフォルトでループを使用し、長さがの場合にfor( in ) のみ使用しますundefined

したがって、この関数を使用する場合、正しい順序を想定しても安全だと思います。

$(['a','b','c']).each(function() {
    alert(this);
});
//Outputs "a" then "b" then "c"

これを使用することの欠点は、UI以外のロジックを実行している場合、関数が他のフレームワークに移植できなくなることです。このeach()関数は、おそらくjQueryセレクターで使用するために予約してfor( ; ; )おくとよいでしょう。



4
常にdocumentcloud.github.com/underscoreがあり、_。eachとその他の便利な機能がたくさんあります
w00t

1
私のオブジェクトに長さプロパティがある場合も意味します$ .eachは失敗しますか?例:x = {a: "1"、b: "2"、length:3}。
Onur Topal 2013年

29

使用するループの種類やブラウザによってパフォーマンスに違いがあります。

例えば:

for (var i = myArray.length-1; i >= 0; i--)

一部のブラウザでは、次の2倍の速度です。

for (var i = 0; i < myArray.length; i++)

ただし、配列が巨大であったり、ループしたりしない限り、すべてが十分に高速です。配列のループがあなたのプロジェクト(または他のすべてのプロジェクト)のボトルネックであることを私は真剣に疑っています


5
ループする前に「myArray.length」を変数に格納すると、パフォーマンスの違いが解消されますか?私の推測は「はい」です。
Tomalak、2008年

3
いいえ。「myArray.length」はプロパティであり、オブジェクトのメソッドではありません。値を決定するための計算は行われません。変数に値を格納しても、何も起こりません。
ジェイソン

3
はいあります。プロパティは変数ではありません。get / setコードがあります。
10

12
私が使用する傾向があるfor(var i = myArray.length; i--;)
ケビン

2
明快さと読みやすさのためのコード。現時点で不条理に大規模な配列を使用しているときに、一部のブラウザーでわずかに高速で実行されることはありません。最適化は変更される可能性がありますが、コードの可読性(またはその欠如)は変更されません。他のユーザーが簡単にフォローできるコードを記述し、オプティマイザが自分の期限内に追いつくようにします。
2015

26

ネイティブのArray.forEachメソッドが広くサポートされるようになったことに注意してください。


2
それは何をするためのものか?他の投稿で言及されている問題がありますか(配列の要素の代わりにプロパティをループする)?また、IE8ではサポートされていないため、広くサポートされているとは言えません。
Rauni Lillemets、2011

2
* nixユーザーがそれを軽視するのと同じくらい、IE8はすべてのsub-windows7ユーザーのほとんどです。それはブラウザ市場の大部分です。
sbartell 2011

2
@Rauni -私はあなたのポイントを取ることが、デスクトップデバイス用のIEブラウザのシェアはによると、40%未満であるen.wikipedia.org/wiki/Usage_share_of_web_browsers#Summary_table、とによるとmarketshare.hitslink.com/...、および他のサイトブラウザーの少なくとも8%がIE 9です。つまり、Array.forEachはデスクトップブラウザーの約70%でサポートされているので、「広くサポートされている」ことは不合理ではないと思います。私はチェックしていませんが、モバイルサポート(WebKitおよびOperaブラウザーで)はさらに高い可能性があります。明らかに、地理的にかなりの変動があります。
Sam Dutton

1
更新していただきありがとうございます。「広くサポートされている」と言えるのではないでしょうか。唯一の問題は...ユーザーがこのJSメソッドを使用している場合、彼/彼女はまだそれがサポートされていないときのためのバックアップ方法を記述しなければならないことである
Rauni Lillemets

1
@Rauni-es5-shimとes6-shimを使用して、バックアップ方法を自動的に提供できます。github.com/es-shims/es5-shim
Michiel van der Blonk

24

すべての主要ブラウザの2012年現在のバージョンの回答を更新 -Chrome、Firefox、IE9、Safari、OperaはES5のネイティブarray.forEachをサポートしています。

IE8をネイティブでサポートする何らかの理由がない限り(適切なJS環境を提供するES5-shimまたはChromeフレームをこれらのユーザーに提供できることに注意してください)、言語の適切な構文を使用するほうが簡単です。

myArray.forEach(function(item, index) {
    console.log(item, index);
});

array.forEach()の完全なドキュメントはMDNにあります。


1
実際にコールバックのパラメータを文書化する必要があります。1つ目は要素の値、2つ目は要素のインデックス、3つ目は走査される配列
drewish

私はあなたの言っていることを聞きますが、この場合、それを過度に単純化すると、可能性の全範囲が不明瞭になります。インデックスと値の両方を持つことは、それがfor ... inとfor each ... inの両方の代わりとして機能できることを意味します。キーまたは値を反復することを覚えておく必要がないボーナスがあります。
2012年

1
@Cory:ES5 forEachは、レガシーES3ブラウザーにかなり簡単に追加できます。コードが少ないほど良いコードです。
mikemaccana 2012

2
@nailerこれは配列とオブジェクトで互換的に使用できますか?
hitautodestruct 2013年

1
@hitautodestructオブジェクトではなく配列のプロトタイプの一部です。一般に、コミュニティでは現在、非配列オブジェクトはまだ 'for(var key in object){}'で反復されています。
mikemaccana 2013年

14

配列がスパースの場合、2つは同じではありません。

var array = [0, 1, 2, , , 5];

for (var k in array) {
  // Not guaranteed by the language spec to iterate in order.
  alert(k);  // Outputs 0, 1, 2, 5.
  // Behavior when loop body adds to the array is unclear.
}

for (var i = 0; i < array.length; ++i) {
  // Iterates in order.
  // i is a number, not a string.
  alert(i);  // Outputs 0, 1, 2, 3, 4, 5
  // Behavior when loop body modifies array is clearer.
}

14

forEachを使用してプロトタイプチェーンをスキップする

上記の @nailer の回答の簡単な補足として、Object.keysでforEachを使用すると、hasOwnPropertyを使用せずにプロトタイプチェーンの反復を回避できます。

var Base = function () {
    this.coming = "hey";
};

var Sub = function () {
    this.leaving = "bye";
};

Sub.prototype = new Base();
var tst = new Sub();

for (var i in tst) {
    console.log(tst.hasOwnProperty(i) + i + tst[i]);
}

Object.keys(tst).forEach(function (val) {
    console.log(val + tst[val]);
});

2
くそー、それは卑劣です。これに到達するために、他の50の投稿を読む価値がありました。obj = {"pink": "ducks"、red: "geese"}; Object.keys(obj)=== ["pink"、 "red"]
Orwellophile

14

必要に応じて反復法を選択するべきだと私は思います。実際には、構造を持つネイティブをループしないください。これは非常に遅く Chase Seibertが前に指摘したように、Prototypeフレームワークと互換性がありません。Arrayfor in

JavaScriptを使用する場合は絶対に確認する必要がある、さまざまなループスタイルに関する優れたベンチマークがあります。初期の最適化は行わないでください。ただし、頭の後ろのどこかにそれを保持する必要があります。

for inオブジェクトのすべてのプロパティを取得するために使用します。これは、スクリプトをデバッグするときに特に役立ちます。たとえば、なじみのないオブジェクトを探索するときは、この行を手元に置いておきます。

l = ''; for (m in obj) { l += m + ' => ' + obj[m] + '\n' } console.log(l);

オブジェクト全体(メソッド本体と一緒に)の内容をFirebugログにダンプします。とても便利です。


リンクが壊れています。誰かが別のリンクを持っているなら、確かにベンチマークを見たいと思います。
Billbad

もう壊れていません。
Olli

Foreachループがプロトタイプで壊れていますか?現在、一般的にサポートされているため、プロトタイプで解決すべき問題です。
mvrak 2013年

7

これが私がしたことです。

function foreach(o, f) {
 for(var i = 0; i < o.length; i++) { // simple for loop
  f(o[i], i); // execute a function and make the obj, objIndex available
 }
}

これはあなたがそれをどのように使用するかであり、
これは配列とオブジェクト(HTML要素のリストなど)で動作します

foreach(o, function(obj, i) { // for each obj in o
  alert(obj); // obj
  alert(i); // obj index
  /*
    say if you were dealing with an html element may be you have a collection of divs
  */
  if(typeof obj == 'object') { 
   obj.style.marginLeft = '20px';
  }
});

私はこれを作ったので、提案を受け入れます:)


素晴らしいもの-かなり簡単です!
クリス

6

アイテムの参照方法に基づいて、さまざまな方法を使用します。

現在のアイテムだけが必要な場合は、foreachを使用します。

相対比較を行うためにインデクサーが必要な場合に使用します。(つまり、これは前/次のアイテムとどのように比較されますか?)

パフォーマンスの違いに気づいたことはありません。パフォーマンスの問題が発生するまで、心配する必要はありません。


下記のBnosの回答を参照してください-ここでは...期待したことを実行していないため、これを使用すれば、あらゆる種類の楽しみを得ることができます。記録として、プロトタイプは正しい方法でます
marcus.greasly 2008年

4

(MyArrayというにおけるVAR i)に対する、あなたがオブジェクトをループあまりにも、することができます私は、キーの名前が含まれます、あなたは経由してプロパティにアクセスすることができます[i]はMyArrayという。さらに、オブジェクトに追加するすべてのメソッドもループに含まれます。つまり、jQueryやプロトタイプなどの外部フレームワークを使用する場合、またはオブジェクトのプロトタイプに直接メソッドを追加する場合、ある時点ではポイントしますそれらのメソッド。


4

気を付けて!

たとえば、複数のスクリプトタグがあり、タグ属性の情報を検索している場合、.lengthプロパティはforループで使用する必要があります。これは、単純な配列ではなくHTMLCollectionオブジェクトだからです。

https://developer.mozilla.org/en/DOM/HTMLCollection

foreachステートメントfor(var i in yourList)を使用すると、ほとんどのブラウザーでHTMLCollectionのプロパティとメソッドが返されます。

var scriptTags = document.getElementsByTagName("script");

for(var i = 0; i < scriptTags.length; i++)
alert(i); // Will print all your elements index (you can get src attribute value using scriptTags[i].attributes[0].value)

for(var i in scriptTags)
alert(i); // Will print "length", "item" and "namedItem" in addition to your elements!

getElementsByTagNameがNodeListを返す必要がある場合でも、ほとんどのブラウザはHTMLCollectionを返します:https ://developer.mozilla.org/en/DOM/document.getElementsByTagName


3

配列のforループはプロトタイプと互換性がありません。将来そのライブラリを使用する必要があると思われる場合は、forループを使用することは理にかなっています。

http://www.prototypejs.org/api/array


「そのライブラリを使用する必要があるかもしれない」ことを忘れてください。代わりに、「あなたのJS はそのライブラリを使用する他のものに含まれている可能性がある」と考えてください。
ijw 2009

3

オブジェクトとプロトタイプと配列を使用した「for each」の問題を見てきました

私の理解は、それぞれがオブジェクトのプロパティのためであり、配列ではないということです


3

コードを高速化したい場合はどうでしょうか?

for( var i=0,j=null; j=array[i++]; foo(j) );

これは、forステートメント内にwhileロジックがあるようなもので、冗長性は低くなります。また、firefoxにはArray.forEachとArray.filterがあります。


2
なぜこれはあなたのコードをスピードアップするのですか?このようなステートメントを並べ替えると速度が向上する理由がわかりません。
Rup

3

jsperfによるより短くて最良のコードは

keys  = Object.keys(obj);
for (var i = keys.length; i--;){
   value = obj[keys[i]];// or other action
}

1

Array()。forEachループを使用して並列処理を利用する


4
ブラウザのJavaScriptは、イベントループが並行しているためArray.prototype.forEach、コールバックへの複数の呼び出しを並行して実行しません。
マイクサミュエル


0

注意してください!!!Mac OSでChrome 22.0を使用していますが、for each構文に問題があります。

これがブラウザの問題なのか、JavaScriptの問題なのか、コードのエラーなのかはわかりませんが、非常に奇妙です。オブジェクトの外では完全に機能します。

var MyTest = {
    a:string = "a",
    b:string = "b"
};

myfunction = function(dicts) {
    for (var dict in dicts) {
        alert(dict);
        alert(typeof dict); // print 'string' (incorrect)
    }

    for (var i = 0; i < dicts.length; i++) {
        alert(dicts[i]);
        alert(typeof dicts[i]); // print 'object' (correct, it must be {abc: "xyz"})
    }
};

MyObj = function() {
    this.aaa = function() {
        myfunction([MyTest]);
    };
};
new MyObj().aaa(); // This does not work

myfunction([MyTest]); // This works

0

両者の間には重要な違いがあります。for-inはオブジェクトのプロパティを反復処理するので、ケースが配列の場合は、その要素だけでなく、その「削除」関数も反復処理されます。

for (var i = 0; i < myArray.length; i++) { 
    console.log(i) 
}

//Output
0
1

for (var i in myArray) { 
    console.log(i) 
} 

// Output
0 
1 
remove

と一緒にfor-inを使用できますif(myArray.hasOwnProperty(i))。それでも、配列を反復するときは常にこれを避けてfor(;;)ステートメントを使用することを常に好みます。


0

どちらも非常に似ていますが、わずかな違いがあります。

var array = ["a", "b", "c"];
array["abc"] = 123;
console.log("Standard for loop:");
for (var index = 0; index < array.length; index++)
{
  console.log(" array[" + index + "] = " + array[index]); //Standard for loop
}

この場合の出力は次のとおりです。

ループの標準:

ARRAY [0] = A

ARRAY [1] = B

ARRAY [2] = C

console.log("For-in loop:");
for (var key in array)
{
  console.log(" array[" + key + "] = " + array[key]); //For-in loop output
}

この場合の出力は次のとおりです。

FOR-IN LOOP:

ARRAY [1] = B

ARRAY [2] = C

ARRAY [10] = D

ARRAY [ABC] = 123


0

for inステートメントを使用すると、オブジェクトのすべてのプロパティの名前をループできます。残念ながら、プロトタイプチェーンを通じて継承されたすべてのメンバーもループします。これは、データメンバーに関心がある場合にメソッド関数を提供するという悪い副作用があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.