For-JavaScriptの配列全体

2012年02月17日に質問されました。  ·  閲覧回数 4.3M回  ·  ソース

Dante1986 picture
2012年02月17日

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

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

forEach(instance in theArray)

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

回答

T.J. Crowder picture
2012年02月17日
7239

TL; DR

  • for-inは、セーフガードと一緒に使用するか、少なくとも噛み付く理由を認識していない限り、使用しないでください。
  • あなたの最善の策は通常です

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

しかし、探求することはもっとます、読んでください...


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

私はすぐにあなたがES5にES2015をtranspilingことで、でも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および関連するものを使用する

ES5によって追加されたArray機能に(直接またはポリフィルを使用して)アクセスできる漠然と現代的な環境(つまり、IE8ではない)では、 forEachspec )を使用できます。 MDN ):

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

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

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

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

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

さらに、 forEachは「それらすべてをループする」関数ですが、ES5は、次のような他のいくつかの便利な「配列を処理して実行する」関数を定義しました。

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

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"

let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    let value = a[index];
    console.log(index, value);
}
try {
    console.log(index);
} catch (e) {
    console.error(e);   // "ReferenceError: index is not defined"
}
try {
    console.log(value);
} catch (e) {
    console.error(e);   // "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);
    });
}

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

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

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

for-inを使用するように言われることがありますが、それはfor-in目的ではありませんfor-inは、配列のインデックスではなく、オブジェクトの列挙可能なプロパティをループします。 ES2015(ES6)でも、注文は保証されません。 ES2015 +は、オブジェクトプロパティへの順序を定義しますが( [[OwnPropertyKeys]][[Enumerate]] 、およびObject.getOwnPropertyKeysようにそれらを使用するものを介して)、 for-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低くなることです- 1、配列の最大値であるlength持つことができます。 (たとえば、配列の長さは32ビットの符号なし整数に収まります。) ブログ投稿のコメントで、以前のテストが完全に正しくなかったことを指摘してくれたRobGへの小道具。)

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

// Utility function for antiquated environments without `forEach`
var hasOwn = Object.prototype.hasOwnProperty;
var rexNum = /^0$|^[1-9]\d*$/;
function sparseEach(array, callback, thisArg) {
    var index;
    for (var key in array) {
        index = +key;
        if (hasOwn.call(a, key) &&
            rexNum.test(key) &&
            index <= 4294967294
            ) {
            callback.call(thisArg, array[key], index, array);
        }
    }
}

var a = [];
a[5] = "five";
a[10] = "ten";
a[100000] = "one hundred thousand";
a.b = "bee";

sparseEach(a, function(value, index) {
    console.log("Value at " + index + " is " + value);
});

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

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

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

裏では、配列からfor-inを使用する場合の問題はありません。これは、オブジェクト(配列)によって定義されたイテレーターを使用し、配列は、イテレーターが(プロパティではなく)エントリを反復処理することを定義するためです。 ES5のfor-inとは異なり、エントリにアクセスする順序は、インデックスの番号順です。

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その反復の値とを。 ( donefalse場合はオプション、 valueundefined場合はオプションです。)

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

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

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

真の配列の他に、 lengthプロパティと数値名のプロパティを持つ配列のようなオブジェクトもあります: NodeListインスタンス、 argumentsオブジェクトなど。それらの内容をループしますか?

アレイには上記のオプションのいずれかを使用してください

上記の配列アプローチの少なくとも一部、場合によってはほとんどまたはすべてが、配列のようなオブジェクトに等しくうまく適用されることがよくあります。

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

    Array.prototypeのさまざまな関数は「意図的に汎用」であり、通常はFunction#callまたはFunction#apply介して配列のようなオブジェクトで使用できます。 (この回答の最後にあるホスト提供のオブジェクトについては

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

    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は、オブジェクト(存在する場合)によって提供されるイテレーターを使用しNodeListからのquerySelectorAll NodeListの仕様は、反復をサポートするように更新されました。 getElementsByTagNameからのHTMLCollectionの仕様はそうではありませんでした。

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

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

真の配列を作成する

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

  1. 配列のsliceメソッドを使用する

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

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

    したがって、たとえば、 NodeListを真の配列に変換する場合は、次のようにすることができます。

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

    以下のホスト提供のオブジェクトについては、thisように使用できなくなります。

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

    この機能をサポートするJavaScriptエンジンでES2015のスプレッド構文を使用することも可能です。 for-ofと同様に、これはオブジェクトによって提供されるイテレータを使用し

    var trueArray = [...iterableObject];
    

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

    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;
    });
    

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

ホストが提供する配列のようなオブジェクト(DOMリストやJavaScriptエンジンではなくブラウザが提供するその他のもの)でArray.prototype関数を使用する場合は、ターゲット環境でテストして、ホスト提供のオブジェクトは正しく動作します。 ほとんどは(現在)Array.prototypeメソッドのほとんどが、抽象[[HasProperty]]操作に正直な答えを与えるホスト提供のオブジェクトに依存しているためです。 この記事の執筆時点では、ブラウザーはこれを非常にうまく処理していますが、5.1仕様では、ホストが提供するオブジェクトが正直でない可能性があります。 それは§8.6.2 、そのセクションの始め近くの大きなテーブルの下のいくつかの段落にあります)、それはそれが言う:

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

(ES2015仕様で同等の言い回しを見つけることができませんでしたが、それでも当てはまるはずです。)繰り返しになりますが、これを書いている時点で、最新のブラウザーでホストが提供する一般的な配列のようなオブジェクト[ NodeListインスタンス、例えば]取り扱い[[HasProperty]]正しく、それはテストすることが重要です。)

PatrikAkerstrand picture
2012年02月17日
533

:この回答は、絶望的に時代遅れです。 より最新のアプローチについては、配列で使用可能なメソッドを参照し

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

JavaScriptで配列を反復処理する標準的な方法は、バニラfor -loopです。

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

ただし、このアプローチは、密な配列があり、各インデックスが要素で占められている場合にのみ有効であることに注意してください。 配列がまばらである場合、配列に実際には存在しない多くのインデックスを反復処理するため、このアプローチでパフォーマンスの問題が発生する可能性があります。 この場合、 for .. inループの方が適切な場合があります。 ただしfor..inループもレガシーブラウザで列挙されるため、適切なセーフガードを使用して、配列の目的のプロパティ(つまり、配列要素)のみが実行されるようにする必要があります。追加のプロパティはenumerableとして定義されます。

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

Poonam picture
2012年02月17日
251

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].
}
joeytwiddle picture
2014年05月02日
127

後方にループする

forループはここで言及する価値があると思います:

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

利点:

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

短所:

  • アイテムを逆の順序で処理します。 結果から新しい配列を作成したり、画面に印刷したりした場合、当然、出力は元の順序とは
  • 順序を維持するために兄弟を最初の子としてDOMに繰り返し挿入することは、効率
  • 逆ループは、後輩の開発者を混乱させます。 (見通しによっては、それが有利だと考えるかもしれません。)

私はいつもそれを使うべきですか?

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

通常、パフォーマンスの向上は重要ではありませんが、それは一種の悲鳴です。

「リスト内のすべてのアイテムに対してこれを行うだけです。順序は関係ありません!」

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

順序が重要でなく、効率が懸念される場合(ゲームまたはアニメーションエンジンの最も内側のループで)、逆forループを頼りになるパターンとして使用することが許容される場合があります。 既存のコードで逆forループが表示されても、必ずしも順序が無関係である意味するわけではないことを覚えておいてください。

forEach()を使用する方が良い

一般に、明快さと安全性がよりArray::forEachを使用することをお勧めしました(最近はfor..ofを使用することを好みます)。 逆ループよりもforEachを好む理由は次のとおりです。

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

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

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

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

for..offorEach()どちらが望ましいかについては議論があります。

個人的には、パフォーマンスや縮小化が大きな懸念事項にならない限り、読みやすいものを使用する傾向があります。 そのため、最近はforEach() for..ofではなくmapまたはfilterまたはfindまたは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でアイテムにアクセスし、 Array-out-of-bounds undefinedアイテムの問題を回避します。

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

    条件i--がfalsey値に評価されると(0になると)、ループは反復を停止します。

    秘訣は、 --iとは異なり、末尾のi--演算子はiデクリメントしますが、デクリメントの値を生成することです。 あなたのコンソールはこれを示すことができます:

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

    [5, 5, 4]

    したがって、最後の反復では、 iは以前は1であり、 i--式はそれを0に変更し1 (truthy)を生成するため、条件は合格です。 次の反復で、 i--i-1に変更しますが、 0 (falsey)を生成し、実行がループの最下部からすぐにドロップアウトします。

    従来のフォワードforループでは、 i++++iは交換可能です(Douglas Crockfordが指摘しているように)。 ただし、逆のforループでは、デクリメントは条件式でもあるため、インデックス0のアイテムを処理する場合は、 i--を使用する必要があります。


トリビア

逆のforループに小さな矢印を描き、ウィンクで終わるのが好きな人もいます。

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

クレジットは、逆forループの利点と恐怖を私に示してくれたWYLに送られます。

zzzzBov picture
2012年02月17日
90

一部の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
    }
}

さらに、 ECMAScript5forEachメソッドをArray.prototype追加しました。これは、calbackを使用して配列を列挙するために使用できます(ポリフィルはドキュメントにあるため、古いブラウザーでも引き続き使用できます) :

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

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

Quentin picture
2012年02月17日
46

配列をループする場合は、標準の3部構成のforループを使用します。

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

myArray.lengthキャッシュするか、逆方向に繰り返すことで、パフォーマンスを最適化できます。

gaby de wilde picture
2013年03月10日
36

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

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

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

user2359695 picture
2014年06月21日
36

私はこれが古い投稿であることを知っています、そしてすでにたくさんの素晴らしい答えがあります。 もう少し完全を期すために、 AngularJSを使用して別のものを投入すると考えました。 もちろん、これはAngularを使用している場合にのみ適用されますが、それでも、とにかくそれを置きたいと思います。

angular.forEachは、2つの引数とオプションの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
});

ある配列から別の配列にアイテムをコピーするのに役立つもう1つの方法は

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);
});

組み込みのバニラフレーバーのforループとは対照的に、 angular.forEach関数を使用することには賛否両論があります。

長所

  • 読みやすさ
  • 書きやすさ
  • 利用可能な場合、 angular.forEachはES5forEachループを使用します。 ここで、forEachループはforループよりもはるかに遅いため、短所のセクションで効率を上げます。 一貫性があり、標準化されているのは良いことなので、私はこれをプロとして言及します。

次の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番目のアプローチを使用してトリプル埋め込みforループを記述したため、読み取りと書き込みが非常に困難でした。

短所

  • 効率。 angular.forEachとネイティブのforEachはどちらも、通常のforループよりもはるかに遅いです....約90%遅くなります。 したがって、大規模なデータセットの場合は、ネイティブのforループに固執するのが最善です。
  • 休憩、続行、またはサポートの返却はありません。 continueは実際には「事故」によってサポートされています。 angular.forEachを続行するには、 angular.forEach(array, function(item) { if (someConditionIsTrue) return; });ような関数にreturn;ステートメントを入力するだけです。その反復の関数から続行します。 これは、ネイティブのforEachがbreakまたはcontinueもサポートしていないためです。

他にもいろいろな長所と短所があると思いますので、よろしければお気軽に追加してください。 要するに、効率が必要な場合は、ループのニーズに合わせてネイティブのforループだけを使用する必要があると思います。 しかし、データセットが小さく、読みやすさと書き込み可能性と引き換えにある程度の効率をあきらめても問題がない場合は、必ずその悪い子にangular.forEachを投げてください。

nmoliveira picture
2013年04月10日
33

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
  }
);
Zaz picture
2016年05月27日
31

ECMAScript 6以降:

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

ここで、 ofは、 in関連する奇妙なことを回避し、他の言語のforループのように機能させ、 letiバインドします。関数内ではなく、ループ内。

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