はじめに
自分自身が繰り返し構文、反復処理メソッドをなんとなくで使っている気がして、一度一通り勉強しなおそうということで記事にしました。
繰り返し構文、反復処理メソッド一覧
- 繰り返し構文
- for
- for...in
- for...of
- do while
- while
- 反復処理メソッド
- forEach
- map
- filter
- reduce
よく使われる、よく聞く繰り返し処理を列挙しました。
for
const array = [1, 2, 3];
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
// => 1
// => 2
// => 3
スタンダードな繰り返し文。
上記のコードでは、変数i
が実行回数を保持し、for
文の中の処理が終わったら変数i
に 1 ずつ足して実行回数をカウントする。変数i
が配列の長さ分より数値が大きくなったら処理終了。
繰り返し条件の変更もしやすく汎用性が高い半面、パッと見で何の処理を行う繰り返し文なのかが分かりづらい特徴がある。
for...of
const array = ["foo", "bar", "baz"];
for (const i of array) {
console.log(i);
}
// => foo
// => bar
// => baz
基本は配列に有効な繰り返し文。
オブジェクトのプロパティーのキーだけ出力したい、プロパティーの値だけ出力したいといった場合には、下記のようにオブジェクトを配列に変換する処理をはさむ必要がある。
例.プロパティーのキーを出力
const array = { a: 1, b: 2, c: 3 };
const newArray = Object.keys(array); // newArray => ["a", "b", "c"]
for (const key of newArray) {
console.log(key);
}
// => a
// => b
// => c
例.値を出力
const array = { a: 1, b: 2, c: 3 };
const newArray = Object.values(array); // newArray => ["1", "2", "3"]
for (const value of newArray) {
console.log(value);
}
// => 1
// => 2
// => 3
例.プロパティーのキーと値をセットにして出力
const array = { a: 1, b: 2, c: 3 };
const newArray = Object.entries(array); //newArray => [["a", 1], ["b", 2], ["c", 3]]
for (const entry of newArray) {
console.log(entry);
}
// => ["a", 1]
// => ["b", 2]
// => ["c", 3]
for...in
オブジェクト・配列に対して使える繰り返し文。
for
文と同じように処理条件内で変数を指定して、それをプロパティーのキーにしてプロパティーの値を出力する場合に使いやすい。
実行環境などによって必ずしも順序通りの出力に関して保証されないため、順序を気にせず列挙する場合に推奨。
※順序通りの出力を担保してほしい場合はfor
文が推奨されている。
const array = { a: 1, b: 2, c: 3 };
for (const i in array) {
console.log(`${i}:${array[i]}`);
}
// => a: 1
// => b: 2
// => c: 3
const array = ["foo", "bar", "baz"];
for (const i in array) {
console.log(i);
}
// => 0
// => 1
// => 2
for...in と for...of の違い
処理対象が配列の場合、for...in
はプロパティーのキーに対して繰り返し処理を行うが、for...of
はプロパティーの値に対して処理を行うため適材適所。
処理対象がオブジェクトの場合、for...in
は出力順序に確実性は保証されないがプロパティーのキーもプロパティーの値もアクセスしやすくシンプルで使いやすい。
for...of
は基本オブジェクトに対して使用できないためプロパティーのキーのみもしくはプロパティーの値のみ、もしくはプロパティーのキーと値をセットにした配列のそれぞれを配列に変換してから処理を行う必要がある。
forEach
繰り返し構文ではないが、配列に対して有効な反復処理メソッド。
配列の値を順繰りコールバック関数が一つ一つ処理する、シンプルで使いやすいメソッド。
const array = ["foo", "bar", "baz"];
array.forEach((v) => {
console.log(v);
});
forEach と for...of の違い
forEach
ではbreak
やcontinue
が使えないため、return
などで中断・スキップ処理を別の書き方をする必要があり、break
やcontinue
と違って一目で中断なのかスキップなのかが分かりづらい。
for...of
でインデックスを取得するにはObject.entries
で変換する必要があるが、forEach
では第二引数でindex
を指定することができるのでインデックスを扱いやすい。
基本的には扱いやすいforEach
を使うのがよさそう。
const array = [1, 2, 3];
for (const [index, v] of Object.entries(array)) {
console.log(`index: ${index}, value: ${v}`);
}
// => index: 0, value: 1
// => index: 1, value: 2
// => index: 2, value: 3
for...of で特定の巡回をスキップする
const array = [1, 2, 3, 4, 5];
for (const [index, v] of Object.entries(array)) {
if (index === "3") {
continue;
}
console.log(`index: ${index}, value: ${v}`);
}
// => index: 0, value: 1
// => index: 1, value: 2
// => index: 2, value: 3
// => index: 4, value: 5
forEach で特定の巡回をスキップする
const array = [1, 2, 3, 4, 5];
array.forEach((v, index) => {
if (index === 2) {
return;
}
console.log(v);
});
// => 1
// => 2
// => 4
// => 5
forEach
メソッドは第二引数にindex
を指定することができ、上記では 3 回目でreturn
を指定することでスキップしている。
do...while
指定した条件に対してfalse
になるまで実行を続ける繰り返し構文。
条件は処理を行った後に判定されるため、1 巡目でfalse
となる条件でも 1 回実行されてからループを終了する。
let count = 0;
do {
count++;
console.log(count);
} while (count < 5);
// => 1
// => 2
// => 3
// => 4
// => 5
let count = 10;
do {
count++;
console.log(count);
} while (count < 5);
// => 11 初期値で条件を満たしていても1回実行される
while
do...while
と処理は似ているが、条件の判定が行われてから処理が走る。
let count = 0;
while (count < 5) {
count++;
console.log(count);
}
// => 1
// => 2
// => 3
// => 4
// => 5
let count = 10;
while (count < 5) {
count++;
console.log(count);
}
// 条件がすでにfalseなためログに出力されない
while と for の違い
どちらも似た繰り返し構文だが、for
は繰り返しの回数が決まっている場合、while
は繰り返し回数が決まっておらず条件がfalse
にならない限り処理を続けたい場合で使い分けるのが慣例的。
map
繰り返し構文ではなく反復処理メソッドで、配列の要素一つ一つを順番にコールバック関数の処理を行い、新たな配列を生成する。
const array = [1, 2, 3, 4, 5];
const mapArray = array.map((v) => v * 2);
console.log(mapArray);
// => [2, 4, 6, 8, 10]
filter
こちらも繰り返し構文ではないが反復処理メソッドで、コールバック関数がtrue
を返す要素だけを抽出して新たな配列を生成する。
const array = [1, 2, 3];
const newArray = array.filter((v) => v % 2 === 1);
console.log(newArray);
// => [1, 3]
reduce
コールバック関数で初期値に対して順番に要素を足し合わせて(積み重ねて)、配列から配列以外の累積値を生成する反復処理メソッド。
const array = [1, 2, 3];
const newArray = array.reduce((accu, curr) => accu + curr);
console.log(newArray);
// => 6 初期値であるaccuには0が入り、0 + 1 + 2 + 3 = 6となる
オブジェクトに対する forEach、map、filter、reduce
上記の反復処理メソッドは基本的に配列に対する処理を得意としている。
オブジェクトに対して使用するためにはObject.values
やObject.entries
などを使用して配列に変換する前段階が必要。
まとめ
構文 | 主な対象 | 使用場面 |
---|---|---|
for | なんでも OK | 繰り返し回数が決まっている処理 |
for...in | 配列・オブジェクト | 配列ならばキーに対して処理を行いたい場合に オブジェクトならば出力順序の正確さを求めない場合 |
for...of | 配列 | プロパティーの値に対して処理を行いたい場合 |
while | なんでも OK | 条件がfalse にならない限り繰り返したい処理 |
do while | なんでも OK | 条件がfalse にならない限り繰り返したい処理かつ 1 回は処理を行いたい場合 |
forEach | 配列 | 配列からコールバック関数で汎用的な処理をしたい場合) |
map | 配列 | 配列からコールバック関数による処理で新たな配列を生成したい場合・ |
filter | 配列 | 配列からコールバック関数による処理でtrue を返す要素を抽出した新たな配列を生成したい場合・ |
reduce | 配列 | 配列からコールバック関数による処理で配列から配列以外の要素の累積値を生成したい場合・ |