JavaScript-myArray.forEachとforループのニュアンス


88

私は使用を提案する多くの質問を見てきました:

for (var i = 0; i < myArray.length; i++){ /* ... */ }

の代わりに:

for (var i in myArray){ /* ... */ }

配列の場合、一貫性のない反復のため(ここを参照)。


しかし、オブジェクト指向ループを好むように見えるものを見つけることができないようです:

myArray.forEach(function(item, index){ /* ... */ });

これは私にはもっと直感的に思えます。

現在のプロジェクトでは、IE8の互換性が重要であり、Mozillaのポリフィルの使用を検討していますが、これがどのように機能するかは100%わかりません。

  • 標準のforループ(上記の最初の例)と最近のブラウザーによるArray.prototype.forEach実装の間に違いはありますか?
  • 最近のブラウザーの実装と上記にリンクされているMozillaの実装(特にIE8に関連)の間に違いはありますか?
  • パフォーマンスはそれほど問題ではなく、反復されるプロパティとの一貫性のみです。

6
それはすることはできませんbreakからforEach。しかし、大きな利点は、関数を使用して新しいスコープを作成することです。ポリフィルを使用すると、問題が発生することはありません(少なくとも私は問題に遭遇していません)。
hgoebl 2014年

古いIEを持つことができるの問題は、シム自体が、壊れた配列コンストラクタ/リテラルWRTではないことや、他の壊れた方法する必要があり、同様にしてDOMオブジェクトをarraylikeするWRT。私のテストでは、仕様に準拠したこのようなシム化されたメソッドが示されています(MDNのシムはテストされていません)。holesundefinedslicehasOwnPropertyes5 shim
Xotic750

1
そして、forループから抜け出すために、それsomeが目的です。
Xotic750

1
「しかし、私はオブジェクト指向ループを好むように見えるものを見つけることができないようです:」私はむしろそれを機能的な方法と命令的と呼びたいです。
Memke、2016年

を使用Array.find()して、最初の一致を見つけた後にループを抜けることができます。
Mottie 2016

回答:


121

forループとforEachメソッドの最も実質的な違いは、前者の場合break、ループから抜け出す可能性があることです。にcontinue渡された関数から戻るだけでシミュレーションできますがforEach、ループを完全に停止する方法はありません。

それ以外に、2つは実質的に同じ機能を実行します。もう1つの小さな違いは、変数の巻き上げにより、forループ内のインデックス(およびすべての変数を含む)のスコープに関係します。

// 'i' is scoped to the containing function
for (var i = 0; i < arr.length; i++) { ... }

// 'i' is scoped to the internal function
arr.forEach(function (el, i) { ... });

ただし、これforEachははるかに表現力があり、配列の各要素を反復処理する意図を表し、インデックスだけでなく要素への参照を提供します。全体的には、個人的な好みが主なものですが、が使えればforEachおすすめです。


2つのバージョンの間には、特にパフォーマンスに関して、さらにいくつかの大きな違いがあります。実際、このjsperfテストでforEach示されているように、単純なforループはメソッドよりもかなりパフォーマンスが優れています。

このようなパフォーマンスが必要かどうかはあなた次第であり、ほとんどの場合、スピードよりも表現力を優先します。この回答に記載されているように、この速度の違いは、スパース配列を操作するときの基本ループとメソッド間のわずかなセマンティックの違いが原因である可能性があります

の動作が必要ない場合forEachや、ループを早期に抜ける必要がある場合_.eachは、代わりにLo-Dashを使用できます。これは、クロスブラウザでも機能します。jQueryを使用している場合は、同様のも提供$.eachします。各バリエーションでコールバック関数に渡される引数の違いに注意してください。

forEachポリフィルについては、そのルートに進むことを選択した場合、古いブラウザーで問題なく動作するはずです。)


1
ライブラリバージョンeachはのECMA5仕様と同じように動作せずforEach、すべての配列を高密度として扱う傾向があります(ご存知であればIEのバグを回避するため)。それ以外の場合は「問題」になる可能性があります。参考としてgithub.com/es-shims/es5-shim/issues/190
Xotic750

7
またArray.prototype.some、真の値を返すまで、または配列を完全にループするまでループするような、ブレークを可能にするいくつかのプロトタイプメソッドもあります。Array.prototype.everyと似てArray.prototype.someいますが、偽の値を返すと停止します。
アクセルドゥク2014年

さまざまなブラウザやそのようなシムでいくつかのテスト結果を確認したい場合は、ci.testling.com
Xotic750 /

また、Array.prototype.forEachを使用すると、コードが拡張機能のなすがままになります。たとえば、ページに埋め込むコードを記述している場合、Array.prototype.forEachが他の何かで上書きされる可能性があります。
マーブルデーモン

2
@MarbleDaemonその可能性は非常に小さいため、事実上不可能であり、無視できます。Array.prototype.forEach互換性のないバージョンで上書きすると、非常に多くのライブラリが壊れる可能性があり、その理由でそれを回避しても、とにかく役に立ちません。
Alexis King

12

Array.forEachよりもはるかに優れたカスタムforeach関数を使用できます。

これを一度コードに追加する必要があります。これにより、配列に新しい関数が追加されます。

function foreach(fn) {
    var arr = this;
    var len = arr.length;
    for(var i=0; i<len; ++i) {
        fn(arr[i], i);
    }
}

Object.defineProperty(Array.prototype, 'customForEach', {
    enumerable: false,
    value: foreach
});

次に、Array.forEachのような任意の場所で使用できます。

[1,2,3].customForEach(function(val, i){

});

唯一の違いは3倍高速です。https://jsperf.com/native-arr-foreach-vs-custom-foreach

更新:新しいChromeバージョンでは、.forEach()のパフォーマンスが改善されました。ただし、このソリューションは他のブラウザーで追加のパフォーマンスを提供できます。

JSPerf


4

多くの開発者(Kyle Simpsonなど).forEachは、配列に副作用があることを示し.map、純粋な関数を使用することを推奨しています。forループは、既知のループ数や、プログラミング言語の大部分での幅広いサポートにより通信が容易になるため適合しないその他のケースの汎用ソリューションとしてうまく適合します。

例えば

/* For Loop known number of iterations */
const numberOfSeasons = 4;
for (let i = 0; i < numberOfSeasons; i++) {
  //Do Something
}

/* Pure transformation */
const arrayToBeUppercased = ['www', 'html', 'js', 'us'];
const acronyms = arrayToBeUppercased.map((el) => el.toUpperCase));

/* Impure, side-effects with .forEach */
const acronymsHolder = [];
['www', 'html', 'js', 'us'].forEach((el) => acronymsHolder.push(el.toUpperCase()));

慣習的には、これが最良のように見えますが、コミュニティは新しい反復プロトコルfor inループに関する慣習に実際に着手していません。一般に、JSコミュニティは採用に向いていると思われるFPの概念に従うことをお勧めします。

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