JavaScriptの配列に対するfor-each


4684

JavaScriptを使用して配列内のすべてのエントリをループするにはどうすればよいですか?

私はそれがこのようなものだと思った:

forEach(instance in theArray)

theArray私の配列はどこですか、これは正しくないようです。


16
私はそれを探しましたが、私は探してforEach いましたfor
前述の

6
ECMAScript  6には「for ... of」構造が含まれる可能性があります。詳細については、for ... of(MDN)を参照してください。すでに最新のFirefoxバージョンで試すことができます。
Slaven Rezic 2013

36
Array.ForEachは、JavaScriptの各for配列のfor()よりも約95%遅くなります。このパフォーマンステストをオンラインで参照してください:coderwall.com/p/kvzbpaを介したjsperf.com/fast-array-foreach
molokoloco

77
多くの状況で、95%遅くなることは重要ではありませんblog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html
David Sykes

7
対照的に、Pythonでは、従来のforループを使用するよりも関数を使用する方が効率的です。(それを考えるi < leni++、むしろインタプリタによるよりも、エンジンによって行うことができる。)
joeytwiddle

回答:


7022

TL; DR

  • for-in安全対策を講じて使用するか、少なくとも噛み付く可能性がある理由を少なくとも認識していない限り、使用しないでください。
  • あなたの最善の策は通常です

    • for-ofループ(ES2015 +のみ)
    • Array#forEachspec| MDN)(またはその親族someなど)(ES5 +のみ)、
    • シンプルな昔ながらのforループ
    • またはfor-inセーフガード付き。

しかし、さらに多くのことを探索し、読み進めてください...


JavaScriptには、配列および配列のようなオブジェクトをループするための強力なセマンティクスがあります。私は答えを2つの部分に分けました:本物の配列のオプションと、オブジェクト、その他の反復可能オブジェクト(ES2015 +)、DOMコレクションなど、配列に似たもののオプションですarguments

ES2015をES5にトランスパイルすることで、ES5エンジンでもES2015オプションをすぐに使用できることにすぐに気づきます。詳細については、「ES2015トランスパイル」/「ES6トランスパイル」を検索してください...

さて、私たちのオプションを見てみましょう:

実際の配列の場合

現在最も広くサポートされているバージョンであるECMAScript 5( "ES5")には3つのオプションがあり、ECMAScript 2015( "ES2015"、 "ES6")にはさらに2 つのオプションが追加されています。

  1. 使用forEachおよび関連(ES5 +)
  2. 単純なforループを使用する
  3. 正しく使うfor-in
  4. 使用するfor-of(暗黙的にイテレーターを使用する)(ES2015 +)
  5. イテレータを明示的に使用する(ES2015 +)

詳細:

1.使用forEachおよび関連

ArrayES5によって追加された機能に(直接またはポリフィルを使用して)アクセスできる、漠然としたモダンな環境(IE8ではない)では、forEachspec| MDN)を使用できます。

var a = ["a", "b", "c"];
a.forEach(function(entry) {
    console.log(entry);
});

forEach コールバック関数と、オプションで、使用する値を受け入れます thisそのコールバックを呼び出すときます(上記では使用されていません)。コールバックは、配列内の各エントリに対して順番に呼び出され、スパース配列に存在しないエントリをスキップします。上記の引数は1つしか使用していませんが、コールバックは次の3つで呼び出されます。各エントリの値、そのエントリのインデックス、反復する配列への参照(関数にまだ便利なものがない場合) )。

IE8のような古いブラウザー(NetAppsが2016年9月の執筆時点で4%をわずかに超える市場シェアを示している)をサポートしていない限りforEach、シムなしで汎用のWebページで楽しく使用できます。廃止されたブラウザをサポートする必要がある場合は、シミング/ポリフィリングforEachを簡単に実行できます(いくつかのオプションについては、「es5 shim」を検索してください)。

forEach インデックス変数と値変数は、反復関数への引数として提供され、その反復のみにスコープが適切に設定されているため、包含スコープで宣言する必要がないという利点があります。

各配列エントリに対して関数呼び出しを行う際の実行時のコストが心配な場合は、心配しないでください。詳細

さらに、forEach「それらすべてをループする」関数ですが、ES5は、以下を含む、他のいくつかの便利な「配列を操作して実行する」関数を定義しました。

  • every(コールバックが最初に戻るとき、falseまたは何かが間違っているときにループを停止します)
  • some(コールバックが最初に戻ったとき、trueまたは真実の何かがループしたときに停止します)
  • filter(filter関数が返す要素を含む新しい配列を作成し、trueそれが返す要素を省略しますfalse
  • map (コールバックによって返された値から新しい配列を作成します)
  • reduce (コールバックを繰り返し呼び出して値を作成し、前の値を渡します。詳細については仕様を参照してください。配列の内容やその他多くの内容を合計するのに役立ちます)
  • reduceRight(と同様reduceですが、昇順ではなく降順で機能します)

2.単純なforループを使用する

時々古い方法が最善です:

var index;
var a = ["a", "b", "c"];
for (index = 0; index < a.length; ++index) {
    console.log(a[index]);
}

配列の長さは、ループ中に変更されません、それがパフォーマンスに敏感なコード(そう)になら、フロントまでの長さをつかんで少し複雑なバージョンがあるかもしれない小さな少し速く:

var index, len;
var a = ["a", "b", "c"];
for (index = 0, len = a.length; index < len; ++index) {
    console.log(a[index]);
}

および/または逆算:

var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --index) {
    console.log(a[index]);
}

しかし、最新のJavaScriptエンジンを使用する場合、最後の部分を気にする必要はほとんどありません。

ES2015以降では、インデックス変数と値変数をforループに対してローカルにすることができます。

let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    let value = a[index];
    console.log(index, value);
}
//console.log(index);   // would cause "ReferenceError: index is not defined"
//console.log(value);   // would cause "ReferenceError: value is not defined"

そして、それを行うと、ループの反復ごとにだけでvalueなく、index再作成されます。つまり、ループ本体で作成されたクロージャーは、その特定の反復用に作成されたindex(およびvalue)への参照を保持します。

let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
    divs[index].addEventListener('click', e => {
        console.log("Index is: " + index);
    });
}

5つのdivがある場合、最初をクリックした場合は「インデックスは:0」となり、最後をクリックした場合は「インデックスは:4」となります。の代わりにを使用すると、これは機能しませvarlet

3. 正しく使用するfor-in

使用するようfor-inに言われるでしょうが、それが目的ではありませんfor-in。配列のインデックスではなく、オブジェクトの列挙可能なプロパティをfor-inループします。ES2015(ES6)であっても、順序は保証されません。ES2015 +は、オブジェクトのプロパティへの順序を定義し(経て、、およびそれらを使用する事が好きです)、それはそれは定義されていませんでしたその順序をたどります。しかし、ES2020はそうしました。(この他の回答の詳細[[OwnPropertyKeys]][[Enumerate]]Object.getOwnPropertyKeysfor-in。)

for-in配列での実際の使用例は次のとおりです。

  • それはだまばらな配列を持つ大規模なそれでギャップ、または
  • 非要素プロパティを使用していて、それらをループに含めたい

最初の例のみを見るfor-in:適切な保護手段を使用すれば、を使用してこれらの疎配列要素にアクセスできます。

// `a` is a sparse array
var key;
var a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (key in a) {
    if (a.hasOwnProperty(key)  &&        // These checks are
        /^0$|^[1-9]\d*$/.test(key) &&    // explained
        key <= 4294967294                // below
        ) {
        console.log(a[key]);
    }
}

3つのチェックに注意してください。

  1. オブジェクトがその名前で独自のプロパティを持っている(プロトタイプから継承したものではない)。

  2. キーがすべて10進数であること(例:科学表記ではなく通常の文字列形式)、および

  3. 数値に強制変換されたときのキーの値が<= 2 ^ 32-2(4,294,967,294)であること。その数はどこから来たのですか?これは、仕様の配列インデックスの定義の一部です。その他の数値(非整数、負の数値、2 ^ 32-2より大きい数値)は配列インデックスではありません。それは2 ^ 32だ理由- 2 -それは2 ^ 32よりも低い方の最大インデックス値せることである1、配列の最大値でlength持つことができます。(たとえば、配列の長さは32ビットの符号なし整数に適合します。)私のブログ投稿のコメントで、以前のテストが正しくなかったことを指摘したRobGへの賛成です。)

もちろん、インラインコードではそれを行いません。ユーティリティ関数を作成します。おそらく:

4.使用for-of(暗黙的にイテレータを使用)(ES2015 +)

ES2015はJavaScriptにイテレータを追加しました。イテレータを使用する最も簡単な方法は、新しいfor-ofステートメントです。次のようになります。

const a = ["a", "b", "c"];
for (const val of a) {
    console.log(val);
}

カバーの下で、配列からイテレータを取得してループし、値を取得します。for-inオブジェクト(配列)で定義されたイテレータを使用し、配列はそのイテレータが(プロパティではなく)エントリを反復することを定義しているため、これにはの問題はありません。for-inES5 とは異なり、エントリにアクセスする順序は、インデックスの番号順です。

5.イテレータを明示的に使用する(ES2015 +)

イテレータを 明示的に使用したい場合があります。あなたもそれを行うことができますが、それよりもはるかに不格好ですfor-of。次のようになります。

const a = ["a", "b", "c"];
const it = a.values();
let entry;
while (!(entry = it.next()).done) {
    console.log(entry.value);
}

イテレータは、仕様のイテレータ定義に一致するオブジェクトです。このnextメソッドは、呼び出すたびに新しい結果オブジェクトを返します。結果オブジェクトには、doneそれが完了したかどうかを示すプロパティvalueと、その反復の値を持つプロパティがあります。(doneそれは次のようになります場合は、オプションでfalsevalueそれが可能ならば省略可能ですundefined。)

の意味はvalueイテレータによって異なります。配列は、反復子を返す(少なくとも)3つの関数をサポートします。

  • values():これは私が上で使用したものです。それは、各イテレータ返すvalue(その反復の配列エントリであるが"a""b"、および"c"前述の例で)。
  • keys():それぞれvalueがその反復のキーであるイテレーターを返します(a上記の例では"0"、それが、then "1"、thenになります"2")。
  • entries():それぞれvalue[key, value]その反復の形式の配列であるイテレーターを返します。

配列のようなオブジェクトの場合

真の配列の他に、インスタンスやオブジェクトなど、数値の名前を持つプロパティとプロパティを持つ配列のようなオブジェクトもあります。それらのコンテンツをループするにはどうすればよいですか?lengthNodeListarguments

上記のオプションのいずれかを配列に使用する

上記の配列のアプローチの少なくともいくつか、そしておそらくほとんどまたはすべてが、配列のようなオブジェクトに頻繁に等しく適用されます。

  1. 使用forEachおよび関連(ES5 +)

    のさまざまな関数Array.prototypeは「意図的に一般的」であり、通常はFunction#callまたはを介して配列のようなオブジェクトで使用できますFunction#apply。(この回答の最後にあるホスト提供オブジェクトの警告を参照してください。ただし、これはまれな問題です。)

    のプロパティで使用forEachしたいとします。あなたはこれをするでしょう:NodechildNodes

    Array.prototype.forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });

    これを頻繁に行う場合は、関数参照のコピーを変数に取り込み、再利用することができます。例:

    // (This is all presumably in some scoping function)
    var forEach = Array.prototype.forEach;
    
    // Then later...
    forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });
  2. 単純なforループを使用する

    明らかに、単純なforループは配列のようなオブジェクトに適用されます。

  3. 正しく使うfor-in

    for-in配列と同じセーフガードを使用すると、配列のようなオブジェクトでも機能するはずです。上記の#1でホストが提供するオブジェクトに関する警告が適用される場合があります。

  4. 使用するfor-of(暗黙的にイテレーターを使用する)(ES2015 +)

    for-ofオブジェクトが提供するイテレータ(存在する場合)を使用します。これには、ホスト提供のオブジェクトが含まれます。たとえば、NodeListfrom の仕様はquerySelectorAll反復をサポートするように更新されました。HTMLCollectionfrom の仕様getElementsByTagNameはそうではありませんでした。

  5. イテレータを明示的に使用する(ES2015 +)

    #4を参照してください。

真の配列を作成する

また、配列のようなオブジェクトを真の配列に変換したい場合もあります。それを行うのは驚くほど簡単です:

  1. slice配列の方法を使用する

    slice配列のメソッドを使用できます。これは、上記の他のメソッドと同様に「意図的にジェネリック」であるため、次のように配列のようなオブジェクトで使用できます。

    var trueArray = Array.prototype.slice.call(arrayLikeObject);

    たとえば、NodeListaを真の配列に変換する場合は、次のようにします。

    var divs = Array.prototype.slice.call(document.querySelectorAll("div"));

    以下のホスト提供オブジェクトの警告を参照してください。特に、これはIE8以前では失敗し、ホストが提供するオブジェクトをthisそのように使用できないことに注意してください。

  2. スプレッド構文を使用(...

    この機能をサポートするJavaScriptエンジンでES2015のスプレッド構文を使用することもできます。のようにfor-of、これはオブジェクトによって提供されるイテレータを使用します(前のセクションの#4を参照):

    var trueArray = [...iterableObject];

    したがって、たとえば、NodeListaを真の配列に変換する場合、spread構文を使用すると、これは非常に簡潔になります。

    var divs = [...document.querySelectorAll("div")];
  3. 使用する Array.from

    Array.from (スペック) | (MDN)(ES2015 +、ただし簡単にポリフィルされます)は、配列のようなオブジェクトから配列を作成し、オプションで最初にマッピング関数を介してエントリを渡します。そう:

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

    または、特定のクラスの要素のタグ名の配列を取得する場合は、マッピング関数を使用します。

    // Arrow function (ES2015):
    var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);
    
    // Standard function (since `Array.from` can be shimmed):
    var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
        return element.tagName;
    });

ホスト提供のオブジェクトに関する警告

ホストが提供する配列のようなオブジェクト(JavaScriptエンジンではなく、ブラウザーが提供するDOMリストなど)でArray.prototype関数を使用する場合は、ターゲット環境でテストして、ホストが提供するオブジェクトが正しく動作することを確認する必要があります。 。ほとんどは正しく動作しますが(現在)、テストすることが重要です。その理由は、使用する可能性が高いメソッドのほとんどが、ホストが提供するオブジェクトに依存して、抽象操作に正直な答えを返すからです。これを書いている時点では、ブラウザーはこれを非常にうまく行っていますが、5.1仕様では、ホスト提供のオブジェクトが正直ではない可能性を考慮しています。それは§8.6.2にあり、そのセクションの冒頭近くの大きなテーブルの下のいくつかの段落にあります)Array.prototype[[HasProperty]]

ホストオブジェクトは、特に指定のない限り、これらの内部メソッドを任意の方法で実装できます。例えば、一つの可能性は、という点である[[Get]][[Put]]特定のホスト・オブジェクトが実際にフェッチとストアのプロパティ値のためではなく、[[HasProperty]]常に生成

(私はES2015仕様で同等の言い回しを見つけることができませんでしたが、まだケースのようにバインドされています。)ここでも、共通のホストが提供する[最近のブラウザでオブジェクト配列-ように書いて、こののようNodeListたとえば、インスタンス] やるハンドルを[[HasProperty]]正しく、しかしそれはテストすることが重要です。)


44
.forEach効率的に分解できないことも付け加えておきます。ブレークを実行するには、例外をスローする必要があります。
Pijusn 2013年

82
@Pius:ループを解除したい場合は、を使用できますsome。(私forEachも破壊を許可することを望んだでしょうが、彼らは、ええと、私に尋ねませんでした。;
TJクラウダー

6
@TJCrowder本来の目的ではないため、回避策のように見えますが、Trueです。
Pijusn 2013年

8
@ user889030:あなたが必要と,した後k=0、ではありません;。覚えておいてください、プログラミングは細部に細心の注意そのうちの1つは、多くの事、... :-)です
TJクラウダー

5
@JimB:それは上記でカバーされています(そしてlengthメソッドではありません)。:-)
TJクラウダー2017

513

:この答えは絶望的に時代遅れです。より現代的なアプローチについては、アレイで利用可能なメソッドを見てください。関心のある方法は次のとおりです。

  • forEach
  • 地図
  • フィルタ
  • zip
  • 減らす
  • いくつか

JavaScriptで配列を反復する標準的な方法は、バニラforループです。

var length = arr.length,
    element = null;
for (var i = 0; i < length; i++) {
  element = arr[i];
  // Do something with element
}

ただし、この方法が適切なのは、配列が密で、各インデックスが要素で占められている場合のみです。配列がスパースの場合、この方法ではパフォーマンスの問題が発生する可能性があります。これは、配列に実際には存在しない多くのインデックスを反復処理するためです。この場合は、for .. in-ループの方が適しています。ただしfor..in-loopもレガシーブラウザで列挙されるため、または追加のプロパティがenumerable

ECMAScript 5のアレイのプロトタイプでのforEachメソッドがあるでしょうが、それは、従来のブラウザでサポートされていません。したがって、これを一貫して使用できるようにするには、それをサポートする環境(たとえば、サーバーサイドJavaScriptのNode.js)を用意するか、「Polyfill」を使用する必要があります。ただし、この機能のポリフィルは簡単なものであり、コードを読みやすくするため、含めるのに適したポリフィルです。


2
なぜfor(instance in objArray) 正しい使い方ではないのですか?私にはもっとシンプルに見えますが、正しい使い方とは言えないと聞いていますか?
Dante1986

21
インライン長のキャッシングを使用できます。for(var i = 0、l = arr.length; i <l; i ++)
Robert Hoffmann

3
最初の行の終わりのカンマは意図的なものですか、それともタイプミスですか(セミコロンの可能性があります)?
Mohd Abdul Mujib 2013年

6
@ wardha-Web意図的なものです。これにより、単一のvarキーワードで複数の変数を宣言できます。セミコロンを使用した場合はelement、グローバルスコープで宣言されていたはずです(または、JSHintが本番に到達する前に叫んでいたでしょう)。
PatrikAkerstrand 2013年

239

jQueryライブラリを使用している場合は、jQuery.eachを使用できます。

$.each(yourArray, function(index, value) {
  // do your stuff here
});

編集:

質問に従って、ユーザーはjqueryの代わりにJavaScriptのコードを望んでいるので、編集は

var length = yourArray.length;   
for (var i = 0; i < length; i++) {
  // Do something with yourArray[i].
}

2
私はおそらくこの答えを最も頻繁に使うつもりです。これは質問に対する最良の回答ではありませんが、実際にはjQueryを使用する私たちにとって最も単純で最も適切なものになります。私たちもみんなバニラの方法を学ぶべきだと私は思います。あなたの理解を広げることは決して害にはなりません。
mopsyd 2013

47
そのために、jQueryはそれぞれネイティブソリューションよりもはるかに低速です。jQueryは、可能な限り、jQueryではなくネイティブJavaScriptを使用することをお勧めします。jsperf.com/browser-diet-jquery-each-vs-for-loop
Kevin Boss

8
バニラjsを使用できる場合はjQueryの使用を控える
Noe

2
標準のJSに固執し、ネイティブ言語のソリューションがない限り、サードパーティのライブラリを答えに
含め

116

逆方向にループ

ここでは、forループのについて言及するに値すると思います。

for (var i = array.length; i--; ) {
     // process array[i]
}

利点:

  • 一時的なlen変数を宣言したりarray.length、反復ごとに比較したりする必要はありません。どちらも1分間の最適化です。
  • DOMから兄弟を逆の順序で削除する方が、通常はより効率的です。(ブラウザーは、内部配列の要素のシフトを少なくする必要があります。)
  • ループ中、インデックスi以降で配列変更した場合(たとえば、でアイテムを削除または挿入した場合)、前方ループは、左にシフトしたアイテムを位置iにスキップするか、以前のi番目のアイテムを再処理します右シフト。従来のforループでは、処理を必要とする次の項目を指すようにiを更新することができます-1が、反復の方向を単に逆にするだけの方が、多くの場合、よりシンプルエレガントなソリューションです。array[i]
  • 同様に、ネストされた DOM要素を変更または削除する場合、逆の処理でエラー回避できます。たとえば、子を処理する前に、親ノードのinnerHTMLを変更することを検討してください。子ノードに到達すると、子ノードはDOMから切り離され、親のinnerHTMLが書き込まれたときに新しく作成された子に置き換えられます。
  • 利用可能な他のいくつかのオプションよりも、タイプして読む短いです。ES6との間では負けますが。forEach()for ... of

短所:

  • アイテムを逆の順序で処理します。結果から新しい配列を作成したり、画面に印刷したりする場合、当然、出力は元の順序に対して逆になります
  • 兄弟を最初の子としてDOMに繰り返し挿入して順序を維持するのは効率がよくありません。(ブラウザーは、物事を正しくシフトし続ける必要があります。)DOMノードを効率的かつ順番に作成するには、順方向にループし、通常どおりに追加します(「ドキュメントフラグメント」も使用します)。
  • リバースループは、ジュニア開発者を混乱させます。(あなたの見通しに応じて、あなたはそれを利点と考えるかもしれません。)

常に使用する必要がありますか?

一部の開発者は、順方向にループする正当な理由がない限り、デフォルトで逆forループを使用します

通常、パフォーマンスの向上はわずかですが、悲鳴のようなものです。

「リストのすべてのアイテムに対してこれを行うだけで、注文は気になりません!」

しかしある実際にはない、それはあなたがたときに、それらの機会と区別がつかないことから、実際に意思の信頼できる指標行うために気を、そして本当に必要性を逆にループします。そのため、実際には、「ドントケア」の意図を正確に表現するために別の構成が必要になります。これは、現在ECMAScriptを含むほとんどの言語では利用できませんが、たとえばと呼ばれforEachUnordered()ます。

順序が問題ではなく、効率が懸念される場合(ゲームまたはアニメーションエンジンの最も内側のループ)、ループの逆を使用するパターンとして使用することもできます。既存のコードで逆forループが表示されても、必ずしも順序が無関係であるとは限らないことに注意してください。

forEach()を使用する方が良かった

一般的に、明快さと安全性重視される高レベルのコードの場合、以前Array::forEachはループのデフォルトパターンとしてを使用することをお勧めしました(最近ではを使用することを好んでいますfor..of)。forEachリバースループよりも優先する理由は次のとおりです。

  • 読みやすくなります。
  • これは、iがブロック内でシフトされないことを示します(これは、長いループで突然の非表示になる可能性がforありwhileます)。
  • それはあなたに閉鎖のための自由な範囲を与えます。
  • ローカル変数のリークと、外部変数との偶然の衝突(および変異)を減らします。

次に、コードに逆forループが表示された場合、それは正当な理由(おそらく上記の理由の1つ)で逆になっているというヒントです。また、従来のforループを見ると、シフトが発生している可能性があります。

(意図の議論があなたにとって意味をなさない場合、あなたとあなたのコードはプログラミングスタイルとあなたの脳に関するクロックフォードの講義を見ることから利益を得るかもしれません。)

for..of!を使用するのがさらに良くなりました。

かどうかについての議論があるfor..ofか、forEach()好ましいは:

個人的には、パフォーマンスやミニファイが大きな問題にならない限り、私は読みやすいものを何でも使う傾向があります。そのため、最近ではのfor..of代わりにを使用することを好みますがforEach()、常にmapor filterまたはfindorまたはsome該当する場合は常に使用します。(同僚のために、私はめったに使用しませんreduce。)


どのように機能しますか?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

これi--が真ん中の節(通常は比較が表示される)であり、最後の節が空(通常はが表示されるi++)であることがわかります。つまり、継続i--条件としても使用されます。重要なのは、各反復の前に実行およびチェックされることです。

  • どうやってそれを始めることができますか array.length爆発せずますか?

    各反復の前にi--実行されるため、最初の反復では実際に項目にアクセスし、境界外項目のarray.length - 1問題を回避します。 undefined

  • なぜインデックス0の前に反復を停止しないのですか?

    ループは、条件が満たされたときに反復を停止します i--が誤った値に評価される結果が0になると)。

    トリックは、とは異なり--i、末尾のi--演算子は減少しますiが、減少するの値を生成します。あなたのコンソールはこれを実証することができます:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    したがって、最後の反復では、iは以前は1でしたが、i--式はそれを0に変更しますが、実際には1(真実)を生成するため、条件は通過します。次の反復でi-1にi--変更しますが、 0(偽)になるため、実行はすぐにループの最後から抜け出します。

    ループのための従来の前方に、i++及び++i(ダグラス・クロックフォードが指摘するように)交換可能です。ただし、逆のforループでは、デクリメントは条件式でもあるため、i--インデックス0でアイテムを処理する場合は固執する必要があります。


トリビア

一部の人々は、逆forループに小さな矢印を描き、ウィンクで終了するのを好みます:

for (var i = array.length; i --> 0 ;) {

クレジットは、リバースforループの利点と恐怖を見せてくれたWYLに送られます。


3
ベンチマークを追加するを忘れました。また、6502のような8ビットプロセッサでリバースループが大幅に最適化されることを忘れていました。
joeytwiddle 2014年

ここでは、同じ答えがはるかに簡潔に示されています(別の質問について)。
joeytwiddle 2018

84

一部のCスタイル言語はforeach、列挙をループするために使用します。JavaScriptでは、これはfor..inループ構造で行われます

var index,
    value;
for (index in obj) {
    value = obj[index];
}

落とし穴があります。for..inオブジェクトの列挙可能な各メンバーと、そのプロトタイプのメンバーをループします。オブジェクトのプロトタイプを介して継承される値を読み取らないようにするには、プロパティがオブジェクトに属しているかどうかを確認します。

for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}

さらに、ECMAScript 5は、コールバックを使用して配列を列挙するために使用できるforEachメソッドを追加しましたArray.prototype(ポリフィルはドキュメントにあるため、古いブラウザーでも使用できます)。

arr.forEach(function (val, index, theArray) {
    //do stuff
});

Array.prototype.forEachコールバックが戻ったときにが壊れないことに注意することが重要falseです。jQueryUnderscore.jsは、独自のバリエーションeachを提供して、短絡可能なループを提供します。


3
では、通常のforループやCスタイルの言語で見られるようなforeachループのように、ECMAScript 5のforeachループをどのようにして抜け出すのでしょうか。
Ciaran Gallagher

5
@ CiaranG、JavaScriptでは、ループから抜け出すために使用eachできるメソッドを参照するのが一般的ですreturn falseが、forEachこれはオプションではありません。外部のフラグは、すなわち(使用することができif (flag) return;、それだけ、実行が関数本体の残りの部分を妨げるforEachまだコレクション全体を反復継続する。
zzzzBov

43

配列をループする場合は、標準の3つの部分からなるforループを使用します。

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

キャッシングmyArray.lengthまたはそれを逆方向に反復することにより、パフォーマンスを最適化できます。


6
for(var i = 0、length = myArray.length; i <length; i ++)はそれを行うべきです
Edson Medina

5
@EdsonMedinaこれにより、という新しいグローバル変数も作成されlengthます。;)
joeytwiddle 2014年

4
@joeytwiddleはい、しかしそれはこの投稿の範囲を超えています。とにかく、グローバル変数iを作成します。
エドソンメディナ2014年

6
@EdsonMedina申し訳ありませんが、それは完全に間違っていました。,割り当て後に使用しても新しいグローバル導入されないため、提案は問題ありませ。これを別の問題で混乱させていました。=割り当て後に使用すると、新しいグローバルが作成されます
joeytwiddle 14

変数iはループに対してローカルではないことに注意してください。JavaScriptにはブロックスコープがありません。var i, length, arrayItem;この誤解を避けるために、ループの前に宣言することをお勧めします。
ジェームズ

35

私はこれが古い投稿であることを知っており、すでに非常に多くの素晴らしい答えがあります。もう少し完全にするために、AngularJSを使用して別のものを投入すると思いました。もちろん、これは、Angularを使用している場合にのみ当てはまります。

angular.forEach2つの引数とオプションの3番目の引数を取ります。最初の引数は反復するオブジェクト(配列)、2番目の引数は反復関数、オプションの3番目の引数はオブジェクトコンテキスト(基本的にループ内では「this」と呼ばれます)です。

角度のforEachループを使用する方法はいくつかあります。最も単純でおそらく最も使用されるのは

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

ある配列から別の配列に項目をコピーするのに役立つ別の方法は、

var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
    this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);

ただし、これを行う必要はありませんが、以下を実行するだけで、前の例と同等になります。

angular.forEach(temp, function(item) {
    temp2.push(item);
});

現在angular.forEach、組み込みのバニラ風味のforループとは対照的に、関数を使用することの長所と短所があります。

長所

  • 読みやすさ
  • 書き込みが簡単
  • 可能な場合angular.forEachは、ES5 forEachループを使用します。forEachループはforループよりもはるかに遅いので、今度はconsセクションで効率を上げます。一貫性があり、標準化されていることは素晴らしいので、私はこれをプロと呼んでいます。

まったく同じことを行う次の2つのネストされたループについて考えてみます。オブジェクトの2つの配列があり、各オブジェクトに結果の配列が含まれていて、それぞれに文字列(またはその他)であるValueプロパティがあるとします。そして、各結果を反復処理する必要があり、それらが等しい場合は、いくつかのアクションを実行するとします。

angular.forEach(obj1.results, function(result1) {
    angular.forEach(obj2.results, function(result2) {
        if (result1.Value === result2.Value) {
            //do something
        }
    });
});

//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
    for (var j = 0; j < obj2.results.length; j++) {
        if (obj1.results[i].Value === obj2.results[j].Value) {
            //do something
        }
    }
}

これは非常に単純な架空の例ですが、2番目のアプローチを使用して、3つの埋め込みforループを作成しましたが、そのため、読み取りと書き込みが非常に困難でした。

短所

  • 効率。angular.forEach、およびネイティブforEachに関しては、どちらも通常のループよりもはるかに遅くなりforます...約90%遅くなります。したがって、大規模なデータセットの場合は、ネイティブforループを使用することをお勧めします。
  • 中断、継続、または返品のサポートはありません。continue実際に " 事故 " によってサポートされています。続行するには、関数内にステートメントangular.forEachを単純に置くと、その反復のために関数から抜け出します。これは、ネイティブが中断も継続もサポートしていないという事実も原因です。return;angular.forEach(array, function(item) { if (someConditionIsTrue) return; });forEach

他にもさまざまな長所と短所があると思います。必要に応じて自由に追加してください。結論として、効率が必要な場合forは、ループのニーズに合わせてネイティブループのみを使用するようにしてください。しかし、データセットが小さく、読みやすさと書き込み可能性と引き換えにある程度の効率をあきらめても大丈夫な場合は、必ずangular.forEachその悪役を投げてください。


34

配列を空にしても構わない場合:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

xの最後の値が含まyれ、配列から削除されます。shift()whichを使用して、から最初のアイテムを取得および削除することもできますy


4
のようなスパース配列がある場合は機能しません[1, 2, undefined, 3]
M. Grzywaczewski 16

2
...または実際に何か間違っている:[1, 2, 0, 3]または[true, true, false, true]
joeytwiddle

31

A のforeachの実装(jsFiddleで参照)。

function forEach(list,callback) {
  var length = list.length;
  for (var n = 0; n < length; n++) {
    callback.call(list[n]);
  }
}

var myArray = ['hello','world'];

forEach(
  myArray,
  function(){
    alert(this); // do something
  }
);

2
このイテレータは、不必要な長さの計算を行っています。理想的なケースでは、リストの長さは一度だけ計算する必要があります。
MIdhun Krishna

2
@MIdhunKrishna回答とjsFiddleを更新しましたが、思ったほど簡単ではないことに注意してください。この質問を
nmoliveira 2013

2
フルと右の実装では、ここで見つけることができます:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
marciowb

29

おそらくfor(i = 0; i < array.length; i++)ループは最良の選択ではありません。どうして?これがあれば:

var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";

メソッドはfrom array[0]を呼び出しますarray[2]。最初に、これは最初にあなたも持っていない変数を参照し、2番目は配列に変数を持たないでしょう、そして3番目はこれによりコードを太字にします。ここを見て、それは私が使用するものです:

for(var i in array){
    var el = array[i];
    //If you want 'i' to be INT just put parseInt(i)
    //Do something with el
}

そしてそれを関数にしたい場合は、これを行うことができます:

function foreach(array, call){
    for(var i in array){
        call(array[i]);
    }
}

ブレークしたい場合は、もう少しロジック:

function foreach(array, call){
    for(var i in array){
        if(call(array[i]) == false){
            break;
        }
    }
}

例:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

それは返します:

//Hello
//World
//!!!

29

3つの実装がありますforeachjQueryのは、次のように。

var a = [3,2];

$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3

2
コンソールログはデモ用です。それは、それを完全な実行例にすることです。
ラジェシュポール

29

ECMAScript 6以降:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

of関連付けられている奇妙さを回避し、他の言語のループのinように機能させforletバインドする場所i関数内とは対照的に、ループ内。

中括弧({})は、コマンドが1つしかない場合は省略できます(上記の例のように)。


28

今の簡単な解決策は、underscore.jsライブラリを使用することです。などの多くの便利なツールを提供しておりeach、ジョブをネイティブに自動的に委任しますforEach可能な場合ます。

それがどのように機能するかのCodePenの例は次のとおりです:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

こちらもご覧ください


23

for eachネイティブJavaScriptにはループはありません。ライブラリを使用してこの機能を取得するか(私はUnderscore.jsをお勧めforします)、単純なループを使用します。

for (var instance in objects) {
   ...
}

ただし、さらに単純なforループを使用する理由がある場合があることに注意してください(「スタックオーバーフローの質問」を参照してください。配列反復で「for…in」を使用するのはなぜ悪い考えですか?

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}

22

これは、インデックスが0から始まる非スパースリストのイテレータです。これは、document.getElementsByTagNameまたはdocument.querySelectorAllを処理するときの一般的なシナリオです。

function each( fn, data ) {

    if(typeof fn == 'string')
        eval('fn = function(data, i){' + fn + '}');

    for(var i=0, L=this.length; i < L; i++) 
        fn.call( this[i], data, i );   

    return this;
}

Array.prototype.each = each;  

使用例:

例1

var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]

例#2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

各pタグは class="blue"

例3

each.call(document.getElementsByTagName('p'), 
    "if( i % 2 == 0) this.className = data;",
    'red'
);

他のすべてのpタグはclass="red">

例4

each.call(document.querySelectorAll('p.blue'), 
    function(newClass, i) {
        if( i < 20 )
            this.className = newClass;
    }, 'green'
);

そして最後に、最初の20個の青色のpタグが緑色に変更されます

関数として文字列を使用する場合の注意:関数はコンテキスト外で作成され、変数のスコープが確実である場合にのみ使用する必要があります。それ以外の場合は、スコープがより直感的な関数を渡す方が適切です。


21

以下のように、JavaScriptで配列をループする方法はいくつかあります。

for-それは最も一般的なものです。ループするコードの完全なブロック

var languages = ["Java", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
    text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

しばらく -ループ条件が通じている間。最速のループのようです

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do / while-条件がtrueである間もコードのブロックをループし、少なくとも1回は実行します

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

機能ループ - 、forEachmapfilterまたreduceスルー機能(彼らループが、あなたがあなたのアレイに何かをする必要がある場合、彼らはなど、使用されています

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

配列の関数型プログラミングの詳細と例については、ブログ投稿「JavaScriptでの関数型プログラミング:map、filter、reduce」をご覧ください。


小さな修正:forEach新しい関数を返さないArray(実際には何も返さない)ため、「機能的な」ループではなく、単に繰り返すだけです。
ニコラスミン2018年

19

配列で動作するECMAScript 5(JavaScriptのバージョン):

forEach-配列内のすべてのアイテムを反復処理し、各アイテムで必要なことをすべて実行します。

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is #" + (index+1) + " in the musical scale");
});

// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale

場合によっては、いくつかの組み込み機能を使用した配列の操作に関心があります。

マップ -それは、コールバック関数の結果を使用して新しい配列を作成します。このメソッドは、配列の要素をフォーマットする必要がある場合に使用すると便利です。

// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']

reduce-名前が示すように、現在の要素と前回の実行の結果を渡して指定された関数を呼び出すことにより、配列を単一の値に減らします。

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

every-配列内のすべての要素がコールバック関数のテストに合格した場合、trueまたはfalseを返します。

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filter-与えられた関数にtrueを返す要素を持つ配列を返すことを除いて、すべてに非常に似ています。

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]

16

侵入する組み込みの機能はありませんforEach。実行を中断するには、Array#some以下のように使用します。

[1,2,3].some(function(number) {
    return number === 1;
});

これsomeは、配列順に実行されるコールバックのいずれかがtrueを返し、残りの実行を短絡するとすぐにtrueを返すため、機能します。 元の答え は、いくつかの配列プロトタイプを参照してください


13

また、これをリバースループの構成として追加し、この構文も必要な人のために上記の回答を追加します。

var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
    console.log(item);
}

長所:

この利点:最初に参照が既にあるので、後で別の行で宣言する必要はありません。オブジェクト配列をループするときに便利です。

短所:

これは、参照がfalse-falsey(未定義など)の場合はいつでも壊れます。ただし、利点として使用できます。ただし、読みにくくなります。また、ブラウザによっては、元のブラウザよりも高速に動作するように最適化できない場合があります。


12

jQueryの使用方法$.map

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];

1
私は出力が可能性が高いと思います[undefined, 2, undefined, 4, undefined, 6, undefined]

10

ECMAScript 6の構造化解除スプレッド演算子でループを使用する

一部のJavaScriptのベテランは厄介だと考えるかもしれませんが、spreadオペレーターの分解と使用は、ECMAScript 6の初心者にとっては、より人間が読みやすい/美的であることが非常に有用であることが証明されています。ジュニアや他の人はそれが便利だと思うかもしれません。

次の例では、for...ofステートメントと.forEachメソッドを使用します。

実施例6,7、および8は、のような任意の機能ループで使用することができ.map.filter.reduce.sort.every.some。これらのメソッドの詳細については、配列オブジェクトを確認してください。

例1:通常のfor...ofループ-ここではトリックはありません。

let arrSimple = ['a', 'b', 'c'];

for (let letter of arrSimple) {
  console.log(letter);
}

例2:単語を文字に分割する

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

例3:key andでループするvalue

// let arrSimple = ['a', 'b', 'c'];

// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type:
// `arrWithIndex: [number, string][]`

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);

// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on Internet Explorer  unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);

for (let [key, value] of arrWithIndex) {
  console.log(key, value);
}

例4:オブジェクトのプロパティをインラインで取得する

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

例5:必要なオブジェクトのディープオブジェクトプロパティを取得する

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

例6:ある例3で使用します.forEach

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it

arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
  console.log(forEachIndex, mappedIndex, item);
});

例7:ある例4で使用します.forEach

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parentheses
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
  console.log(name, aliasForAge)
});

例8:ある例5で使用します.forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});


7

あなたのアイデアに最も近い方法Array.forEach()は、配列の各要素に対して実行されるクロージャー関数を受け入れるを使用することです。

myArray.forEach(
  (item) => {
    // Do something
    console.log(item);
  }
);

もう1つの実行可能な方法はArray.map()、同じように機能するを使用することですが、次のように、返されるすべての値を取り、それらを新しい配列で返します(基本的に、各要素を新しい要素にマッピングします)。

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]

1
これは間違ってmapいます。配列の要素を変更しません。これは、新しい配列を返します。新しい配列の項目は、古い配列の項目に関数を適用した結果です。
ヘススフランコ

新しい配列を返さないと言ったことはありません。関数によって適用された変更を参照していました。しかし、ここで答えを変更します。
アンテジャブランアダモビッチ

再び間違った、マップは変更しないか、元の配列内のすべての項目で変異し、私は提案してきたとのマップの作品を強調答えに編集コピーのすべてで手つかずの元の配列を残し、オリジナルアイテムの
ジェス・フランコ

7

次のようにforEachを呼び出すことができます。

forEach指定した配列を反復処理し、反復ごとにelement、その反復の値を保持します。インデックスが必要な場合は、i、forEachのコールバック関数の2番目のパラメーターとして。

Foreachは基本的に高次関数であり、別の関数をパラメーターとして使用します。

let theArray= [1,3,2];

theArray.forEach((element) => {
  // Use the element of the array
  console.log(element)
}

出力:

1
3
2

次のように配列を反復処理することもできます。

for (let i=0; i<theArray.length; i++) {
  console.log(i); // i will have the value of each index
}

6

関数arrowでオブジェクトの配列をループしたい場合:

let arr = [{name:'john', age:50}, {name:'clark', age:19}, {name:'mohan', age:26}];

arr.forEach((person)=>{
  console.log('I am ' + person.name + ' and I am ' + person.age + ' old');
})


6

ラムダ構文は通常、Internet Explorer 10以下では機能しません。

私は通常使用します

[].forEach.call(arrayName,function(value,index){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

jQuery ファンであり、すでにjQueryファイルを実行している場合は、インデックスと値パラメーターの位置を逆にする必要があります

$("#ul>li").each(function(**index, value**){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

5

大規模なアレイがある場合は、iterators効率を上げるために使用する必要があります。イテレータは、(のような特定のJavaScriptコレクションの財産でありMapSetStringArray)。でも、内部でfor..of使用iteratorしています。

イテレータは、リスト内のアイテムをストリームのように一度に1つずつ使用できるようにすることで効率を向上させます。イテレータが特別なのは、イテレータがどのようにコレクションを走査するかです。他のループは、それを反復するためにコレクション全体を事前にロードする必要がありますが、イテレータはコレクション内の現在の位置のみを知っている必要があります。

イテレータのnextメソッドを呼び出して、現在のアイテムにアクセスします。次のメソッドはvalue、現在のアイテムのとboolean、コレクションの最後に達したことを示すa を返します。以下は、配列からイテレータを作成する例です。

次のvalues()ようなメソッドを使用して、通常の配列をイテレータに変換します。

    const myArr = [2,3,4]

let it = myArr.values();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

次のSymbol.iteratorようにして、通常の配列をイテレータに変換することもできます。

const myArr = [2,3,4]

let it = myArr[Symbol.iterator]();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

あなたのレギュラーarrayを次のiteratorように変換することもできます:

let myArr = [8, 10, 12];

function makeIterator(array) {
    var nextIndex = 0;
    
    return {
       next: function() {
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
};

var it = makeIterator(myArr);

console.log(it.next().value);   // {value: 8, done: false}
console.log(it.next().value);   // {value: 10, done: false}
console.log(it.next().value);   // {value: 12, done: false}
console.log(it.next().value);   // {value: undefined, done: true}

  • イテレータは本質的に使い果たされます。
  • オブジェクトはiterableデフォルトではありません。for..in値の代わりにキーで機能するため、その場合に使用します。

詳細については、iteration protocol こちらをご覧ください


5

あなたが使いたいならforEach()、それは次のようになります-

theArray.forEach ( element => {
    console.log(element);
});

あなたが使いたいならfor()、それは次のようになります-

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}

4

新しい更新された機能ECMAScript 6(ES6)およびECMAScript 2015に従って、ループで次のオプションを使用できます。

forループ

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

// Output: 0,1,2,3,4

for ... inループ

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

for ... ofループ

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

whileループ

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

する... whileループ

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4

4

パフォーマンス

今日(2019年12月18日)私は自分のテストを行うのMacOS v10.13.6クロームV 79.0で、サファリv13.0.4およびFirefoxのv71.0(64ビット)、(ハイシエラ) -最適化についての結論(およびマイクロ最適化されメリットは小さいがコードの複雑さが増すため、通常はコードに導入する価値はありません)。

  • 従来のfor iAa)は、すべてのブラウザーで高速なコードを書くのに適した選択肢のようです。

  • for-ofAd)のような他のソリューションはすべてグループCにあります通常、Aaより2〜10倍(またはそれ以上)遅くなりますが、小さな配列の場合はコードをわかりやすくするために使用してもかまいません。

  • nAb、Bb、Be)にキャッシュされた配列の長さのループは高速な場合とそうでない場合があります。おそらくコンパイラはこの状況を自動的に検出し、キャッシングを導入します。キャッシュされたバージョンとキャッシュされていないバージョン(Aa、Ba、Bd)の速度の違いは約1%であるため、紹介nマイクロ最適化のようです。

  • i--最後の配列要素(からループが始まるソリューションと同様のAc、Bcのは、おそらく理由はの方法です- )前方のソリューションよりも、通常〜30%遅いCPUのメモリキャッシュのワーキング -前方メモリの読み取りは、CPUのキャッシュのためのより最適)です。このようなソリューションを使用しないことをお勧めします。

詳細

テストでは、配列要素の合計を計算します。小さな配列(10要素)と大きな配列(1M要素)のテストを実行し、それらを3つのグループに分けます。

  • A - forテスト
  • B - whileテスト
  • C-その他/別の方法

クロスブラウザーの結果

テストされたすべてのブラウザーの結果

ここに画像の説明を入力してくださいブラウザ**

10要素の配列

Chromeの結果。ここでマシンのテストを実行できます

ここに画像の説明を入力してください

1,000,000要素の配列

Chromeの結果。ここでマシンのテストを実行できます

ここに画像の説明を入力してください


4

概要:

配列を反復するとき、次の目標の1つを達成したいことがよくあります。

  1. 配列を反復処理して、新しい配列を作成します。

    Array.prototype.map

  2. 配列を反復処理し、新しい配列を作成しないでください。

    Array.prototype.forEach

    for..of ループ

JavaScriptでは、これらの両方の目標を達成するための多くの方法があります。ただし、いくつかは他より便利です。以下に、JavaScriptで配列反復を実行するために一般的に使用されるいくつかのメソッド(最も便利なIMO)を示します。

新しいアレイを作成しています: Map

map()Array.prototype配列のすべての要素を変換して新しい配列を返すことができる関数です。map()引数としてコールバック関数を受け取り、次のように機能します。

let arr = [1, 2, 3, 4, 5];

let newArr = arr.map((element, index, array) => {
  return element * 2;
})

console.log(arr);
console.log(newArr);

map()引数として渡したコールバックは、すべての要素に対して実行されます。次に、元の配列と同じ長さの配列が返されます。この新しい配列要素は、に引数として渡されるコールバック関数によって変換されますmap()

間に明確な違いmapなど別のループメカニズムforEachfor..ofループはつまりmap、完全な古い配列新しい配列と葉を返します(明示的に似思うとそれを操作する場合を除きますsplice)。

また、map関数のコールバックは現在の反復のインデックス番号を2番目の引数として提供することに注意してください。さらに、3番目の引数は、map呼び出された配列を提供しますか?これらのプロパティは非常に役立つ場合があります。

ループを使用して forEach

forEachは、Array.prototypeコールバック関数を引数として取る関数です。次に、配列内のすべての要素に対してこのコールバック関数を実行します。map()関数とは対照的に、forEach関数は何も返しません(undefined)。例えば:

let arr = [1, 2, 3, 4, 5];

arr.forEach((element, index, array) => {

  console.log(element * 2);

  if (index === 4) {
    console.log(array)
  }
  // index, and oldArray are provided as 2nd and 3th argument by the callback

})

console.log(arr);

map関数と同様に、forEachコールバックは現在の反復のインデックス番号を2番目の引数として提供します。また、3番目の引数は、forEach呼び出された配列を提供しますか?

要素をループして for..of

for..ofループは、アレイ(または他の任意の反復可能オブジェクト)のすべての要素をループ。次のように機能します。

let arr = [1, 2, 3, 4, 5];

for(let element of arr) {
  console.log(element * 2);
}

上記の例でelementは、は配列要素を表し、arrループする配列です。名前elementは任意であり、「el」などのその他の名前を選択することもできます。

for..inループとループを混同しないでくださいfor..offor..inループfor..ofは配列要素のみをループするのに対し、配列の列挙可能なすべてのプロパティをループします。例えば:

let arr = [1, 2, 3, 4, 5];

arr.foo = 'foo';

for(let element of arr) {
  console.log(element);
}

for(let element in arr) {
  console.log(element);
}

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