JavaScriptを使用して配列内のすべてのエントリをループするにはどうすればよいですか?
私はそれがこのようなものだと思った:
forEach(instance in theArray)
theArray
私の配列はどこですか、これは正しくないようです。
JavaScriptを使用して配列内のすべてのエントリをループするにはどうすればよいですか?
私はそれがこのようなものだと思った:
forEach(instance in theArray)
theArray
私の配列はどこですか、これは正しくないようです。
回答:
TL; DR
for-in
安全対策を講じて使用するか、少なくとも噛み付く可能性がある理由を少なくとも認識していない限り、使用しないでください。あなたの最善の策は通常です
しかし、さらに多くのことを探索し、読み進めてください...
JavaScriptには、配列および配列のようなオブジェクトをループするための強力なセマンティクスがあります。私は答えを2つの部分に分けました:本物の配列のオプションと、オブジェクト、その他の反復可能オブジェクト(ES2015 +)、DOMコレクションなど、配列に似たもののオプションですarguments
。
ES2015をES5にトランスパイルすることで、ES5エンジンでもES2015オプションをすぐに使用できることにすぐに気づきます。詳細については、「ES2015トランスパイル」/「ES6トランスパイル」を検索してください...
さて、私たちのオプションを見てみましょう:
現在最も広くサポートされているバージョンであるECMAScript 5( "ES5")には3つのオプションがあり、ECMAScript 2015( "ES2015"、 "ES6")にはさらに2 つのオプションが追加されています。
forEach
および関連(ES5 +)for
ループを使用するfor-in
for-of
(暗黙的にイテレーターを使用する)(ES2015 +)詳細:
forEach
および関連Array
ES5によって追加された機能に(直接またはポリフィルを使用して)アクセスできる、漠然としたモダンな環境(IE8ではない)では、forEach
(spec
| 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
ですが、昇順ではなく降順で機能します)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」となります。の代わりにを使用すると、これは機能しません。var
let
for-in
使用するようfor-in
に言われるでしょうが、それが目的ではありませんfor-in
。配列のインデックスではなく、オブジェクトの列挙可能なプロパティをfor-in
ループします。ES2015(ES6)であっても、順序は保証されません。ES2015 +は、オブジェクトのプロパティへの順序を定義し(経て、、およびそれらを使用する事が好きです)、それはそれは定義されていませんでしたその順序をたどります。しかし、ES2020はそうしました。(この他の回答の詳細[[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つのチェックに注意してください。
オブジェクトがその名前で独自のプロパティを持っている(プロトタイプから継承したものではない)。
キーがすべて10進数であること(例:科学表記ではなく通常の文字列形式)、および
数値に強制変換されたときのキーの値が<= 2 ^ 32-2(4,294,967,294)であること。その数はどこから来たのですか?これは、仕様の配列インデックスの定義の一部です。その他の数値(非整数、負の数値、2 ^ 32-2より大きい数値)は配列インデックスではありません。それは2 ^ 32だ理由- 2 -それは2 ^ 32よりも低い方の最大インデックス値せることである1、配列の最大値でlength
持つことができます。(たとえば、配列の長さは32ビットの符号なし整数に適合します。)(私のブログ投稿のコメントで、以前のテストが正しくなかったことを指摘したRobGへの賛成です。)
もちろん、インラインコードではそれを行いません。ユーティリティ関数を作成します。おそらく:
for-of
(暗黙的にイテレータを使用)(ES2015 +)ES2015はJavaScriptにイテレータを追加しました。イテレータを使用する最も簡単な方法は、新しいfor-of
ステートメントです。次のようになります。
const a = ["a", "b", "c"];
for (const val of a) {
console.log(val);
}
カバーの下で、配列からイテレータを取得してループし、値を取得します。for-in
オブジェクト(配列)で定義されたイテレータを使用し、配列はそのイテレータが(プロパティではなく)エントリを反復することを定義しているため、これにはの問題はありません。for-in
ES5 とは異なり、エントリにアクセスする順序は、インデックスの番号順です。
イテレータを 明示的に使用したい場合があります。あなたもそれを行うことができますが、それよりもはるかに不格好です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
それは次のようになります場合は、オプションでfalse
、value
それが可能ならば省略可能ですundefined
。)
の意味はvalue
イテレータによって異なります。配列は、反復子を返す(少なくとも)3つの関数をサポートします。
values()
:これは私が上で使用したものです。それは、各イテレータ返すvalue
(その反復の配列エントリであるが"a"
、"b"
、および"c"
前述の例で)。keys()
:それぞれvalue
がその反復のキーであるイテレーターを返します(a
上記の例では"0"
、それが、then "1"
、thenになります"2"
)。entries()
:それぞれvalue
が[key, value]
その反復の形式の配列であるイテレーターを返します。真の配列の他に、インスタンスやオブジェクトなど、数値の名前を持つプロパティとプロパティを持つ配列のようなオブジェクトもあります。それらのコンテンツをループするにはどうすればよいですか?length
NodeList
arguments
上記の配列のアプローチの少なくともいくつか、そしておそらくほとんどまたはすべてが、配列のようなオブジェクトに頻繁に等しく適用されます。
使用forEach
および関連(ES5 +)
のさまざまな関数Array.prototype
は「意図的に一般的」であり、通常はFunction#call
またはを介して配列のようなオブジェクトで使用できますFunction#apply
。(この回答の最後にあるホスト提供オブジェクトの警告を参照してください。ただし、これはまれな問題です。)
のプロパティで使用forEach
したいとします。あなたはこれをするでしょう:Node
childNodes
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`
});
単純なfor
ループを使用する
明らかに、単純なfor
ループは配列のようなオブジェクトに適用されます。
正しく使うfor-in
for-in
配列と同じセーフガードを使用すると、配列のようなオブジェクトでも機能するはずです。上記の#1でホストが提供するオブジェクトに関する警告が適用される場合があります。
使用するfor-of
(暗黙的にイテレーターを使用する)(ES2015 +)
for-of
オブジェクトが提供するイテレータ(存在する場合)を使用します。これには、ホスト提供のオブジェクトが含まれます。たとえば、NodeList
from の仕様はquerySelectorAll
反復をサポートするように更新されました。HTMLCollection
from の仕様getElementsByTagName
はそうではありませんでした。
イテレータを明示的に使用する(ES2015 +)
#4を参照してください。
また、配列のようなオブジェクトを真の配列に変換したい場合もあります。それを行うのは驚くほど簡単です:
slice
配列の方法を使用する
slice
配列のメソッドを使用できます。これは、上記の他のメソッドと同様に「意図的にジェネリック」であるため、次のように配列のようなオブジェクトで使用できます。
var trueArray = Array.prototype.slice.call(arrayLikeObject);
たとえば、NodeList
aを真の配列に変換する場合は、次のようにします。
var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
以下のホスト提供オブジェクトの警告を参照してください。特に、これはIE8以前では失敗し、ホストが提供するオブジェクトをthis
そのように使用できないことに注意してください。
スプレッド構文を使用(...
)
この機能をサポートするJavaScriptエンジンでES2015のスプレッド構文を使用することもできます。のようにfor-of
、これはオブジェクトによって提供されるイテレータを使用します(前のセクションの#4を参照):
var trueArray = [...iterableObject];
したがって、たとえば、NodeList
aを真の配列に変換する場合、spread構文を使用すると、これは非常に簡潔になります。
var divs = [...document.querySelectorAll("div")];
使用する 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]]
正しく、しかしそれはテストすることが重要です。)
.forEach
効率的に分解できないことも付け加えておきます。ブレークを実行するには、例外をスローする必要があります。
,
した後k=0
、ではありません;
。覚えておいてください、プログラミングは細部に細心の注意そのうちの1つは、多くの事、... :-)です
length
メソッドではありません)。:-)
注:この答えは絶望的に時代遅れです。より現代的なアプローチについては、アレイで利用可能なメソッドを見てください。関心のある方法は次のとおりです。
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」を使用する必要があります。ただし、この機能のポリフィルは簡単なものであり、コードを読みやすくするため、含めるのに適したポリフィルです。
for(instance in objArray)
正しい使い方ではないのですか?私にはもっとシンプルに見えますが、正しい使い方とは言えないと聞いていますか?
var
キーワードで複数の変数を宣言できます。セミコロンを使用した場合はelement
、グローバルスコープで宣言されていたはずです(または、JSHintが本番に到達する前に叫んでいたでしょう)。
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].
}
ここでは、forループの逆について言及するに値すると思います。
for (var i = array.length; i--; ) {
// process array[i]
}
len
変数を宣言したりarray.length
、反復ごとに比較したりする必要はありません。どちらも1分間の最適化です。array[i]
forEach()
for ... of
一部の開発者は、順方向にループする正当な理由がない限り、デフォルトで逆forループを使用します。
通常、パフォーマンスの向上はわずかですが、悲鳴のようなものです。
「リストのすべてのアイテムに対してこれを行うだけで、注文は気になりません!」
しかしある実際にはない、それはあなたがたときに、それらの機会と区別がつかないことから、実際に意思の信頼できる指標行うために気を、そして本当に必要性を逆にループします。そのため、実際には、「ドントケア」の意図を正確に表現するために別の構成が必要になります。これは、現在ECMAScriptを含むほとんどの言語では利用できませんが、たとえばと呼ばれforEachUnordered()
ます。
順序が問題ではなく、効率が懸念される場合(ゲームまたはアニメーションエンジンの最も内側のループ)、ループの逆を使用するパターンとして使用することもできます。既存のコードで逆forループが表示されても、必ずしも順序が無関係であるとは限らないことに注意してください。
一般的に、明快さと安全性が重視される高レベルのコードの場合、以前Array::forEach
はループのデフォルトパターンとしてを使用することをお勧めしました(最近ではを使用することを好んでいますfor..of
)。forEach
リバースループよりも優先する理由は次のとおりです。
for
ありwhile
ます)。次に、コードに逆forループが表示された場合、それは正当な理由(おそらく上記の理由の1つ)で逆になっているというヒントです。また、従来のforループを見ると、シフトが発生している可能性があります。
(意図の議論があなたにとって意味をなさない場合、あなたとあなたのコードはプログラミングスタイルとあなたの脳に関するクロックフォードの講義を見ることから利益を得るかもしれません。)
かどうかについての議論があるfor..of
か、forEach()
好ましいは:
ブラウザーを最大限にサポートするにfor..of
は、イテレーター用のポリフィルが必要です。これにより、アプリの実行速度がわずかに遅くなり、ダウンロードがわずかに大きくなります。
その理由のため(との使用を奨励するmap
とfilter
)、いくつかのフロントエンドのスタイルガイドは禁止for..of
完全に!
しかし、上記の懸念事項はNode.jsアプリケーションには当てはまりませんfor..of
。
個人的には、パフォーマンスやミニファイが大きな問題にならない限り、私は読みやすいものを何でも使う傾向があります。そのため、最近ではのfor..of
代わりにを使用することを好みますがforEach()
、常にmap
or filter
またはfind
orまたは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に送られます。
一部の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
です。jQueryとUnderscore.jsは、独自のバリエーションeach
を提供して、短絡可能なループを提供します。
each
できるメソッドを参照するのが一般的ですreturn false
が、forEach
これはオプションではありません。外部のフラグは、すなわち(使用することができif (flag) return;
、それだけ、実行が関数本体の残りの部分を妨げるforEach
まだコレクション全体を反復継続する。
配列をループする場合は、標準の3つの部分からなるfor
ループを使用します。
for (var i = 0; i < myArray.length; i++) {
var arrayItem = myArray[i];
}
キャッシングmyArray.length
またはそれを逆方向に反復することにより、パフォーマンスを最適化できます。
length
ます。;)
,
割り当て後に使用しても新しいグローバルは導入されないため、提案は問題ありません。これを別の問題で混乱させていました。=
割り当て後に使用すると、新しいグローバルが作成されます。
var i, length, arrayItem;
この誤解を避けるために、ループの前に宣言することをお勧めします。
私はこれが古い投稿であることを知っており、すでに非常に多くの素晴らしい答えがあります。もう少し完全にするために、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
});
ある配列から別の配列に項目をコピーするのに役立つ別の方法は、
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
その悪役を投げてください。
配列を空にしても構わない場合:
var x;
while(x = y.pop()){
alert(x); //do something
}
x
の最後の値が含まy
れ、配列から削除されます。shift()
whichを使用して、から最初のアイテムを取得および削除することもできますy
。
[1, 2, undefined, 3]
。
[1, 2, 0, 3]
または[true, true, false, true]
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
}
);
おそらく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
//!!!
今の簡単な解決策は、underscore.jsライブラリを使用することです。などの多くの便利なツールを提供しておりeach
、ジョブをネイティブに自動的に委任しますforEach
可能な場合ます。
それがどのように機能するかのCodePenの例は次のとおりです:
var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});
Array.prototype.forEach()
。for each (variable in object)
ECMA-357(の一部として廃止されEAX)標準。for (variable of object)
は、Harmony(ECMAScript 6)の提案の一部として使用する反復の次の方法を説明します。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];
...
}
これは、インデックスが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タグが緑色に変更されます
関数として文字列を使用する場合の注意:関数はコンテキスト外で作成され、変数のスコープが確実である場合にのみ使用する必要があります。それ以外の場合は、スコープがより直感的な関数を渡す方が適切です。
以下のように、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>
機能ループ - 、forEach
、map
、filter
また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
(実際には何も返さない)ため、「機能的な」ループではなく、単に繰り返すだけです。
配列で動作する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]
また、これをリバースループの構成として追加し、この構文も必要な人のために上記の回答を追加します。
var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
console.log(item);
}
長所:
この利点:最初に参照が既にあるので、後で別の行で宣言する必要はありません。オブジェクト配列をループするときに便利です。
短所:
これは、参照がfalse-falsey(未定義など)の場合はいつでも壊れます。ただし、利点として使用できます。ただし、読みにくくなります。また、ブラウザによっては、元のブラウザよりも高速に動作するように最適化できない場合があります。
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);
});
あなたのアイデアに最も近い方法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]
map
います。配列の要素を変更しません。これは、新しい配列を返します。新しい配列の項目は、古い配列の項目に関数を適用した結果です。
次のように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
}
ラムダ構文は通常、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);
});
大規模なアレイがある場合は、iterators
効率を上げるために使用する必要があります。イテレータは、(のような特定のJavaScriptコレクションの財産でありMap
、Set
、String
、Array
)。でも、内部で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
こちらをご覧ください。
新しい更新された機能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
今日(2019年12月18日)私は自分のテストを行うのMacOS v10.13.6クロームV 79.0で、サファリv13.0.4およびFirefoxのv71.0(64ビット)、(ハイシエラ) -最適化についての結論(およびマイクロ最適化されメリットは小さいがコードの複雑さが増すため、通常はコードに導入する価値はありません)。
従来のfor i
(Aa)は、すべてのブラウザーで高速なコードを書くのに適した選択肢のようです。
for-of
(Ad)のような他のソリューションはすべてグループCにあります。通常、Aaより2〜10倍(またはそれ以上)遅くなりますが、小さな配列の場合はコードをわかりやすくするために使用してもかまいません。
n
(Ab、Bb、Be)にキャッシュされた配列の長さのループは、高速な場合とそうでない場合があります。おそらくコンパイラはこの状況を自動的に検出し、キャッシングを導入します。キャッシュされたバージョンとキャッシュされていないバージョン(Aa、Ba、Bd)の速度の違いは約1%であるため、紹介n
はマイクロ最適化のようです。
i--
最後の配列要素(からループが始まるソリューションと同様のAc、Bcのは、おそらく理由はの方法です- )前方のソリューションよりも、通常〜30%遅いCPUのメモリキャッシュのワーキング -前方メモリの読み取りは、CPUのキャッシュのためのより最適)です。このようなソリューションを使用しないことをお勧めします。
テストでは、配列要素の合計を計算します。小さな配列(10要素)と大きな配列(1M要素)のテストを実行し、それらを3つのグループに分けます。
for
テストwhile
テストクロスブラウザーの結果
テストされたすべてのブラウザーの結果
10要素の配列
1,000,000要素の配列
配列を反復するとき、次の目標の1つを達成したいことがよくあります。
配列を反復処理して、新しい配列を作成します。
Array.prototype.map
配列を反復処理し、新しい配列を作成しないでください。
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
など別のループメカニズムforEach
とfor..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..of
。for..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);
}
forEach
いましたfor
。