はじめに
JavaScriptで配列やオブジェクトの繰り返し処理を書くときに、いつもググっていませんか?
for...in
なのか、for...of
なのか
はたまたfor
を使うか、while
を使うのか
わたしはググっていました。
for
とwhile
ならわかりますが、for...in
とfor...of
がいつもふわっとしています。
しっかり基礎をおさえて、繰り返し処理のググりとおさらばします。
while系
while
とdo...while
があります。
どちらもループ処理を実施する回数が決まっていない場合に適しています。
while
ループを実施するための条件判定を、処理の実施前に行います。
条件の内容によっては、一度もループをしないこともあります。
while (条件式) {
// 何らかの処理
}
do...while
ループを実施するための条件判定を、処理の実施後に行います。
どんな条件であっても、必ず1度は処理を実施します。
do {
// 何らかの処理
} while(条件式)
2つの違い
while
とdo...while
はどちらも条件式がtrueである間、ずっと繰り返し処理を実施します。
大きな違いは、条件判定を前にするか、後にするか、です。
以下のコードは、その違いが顕著にあらわれています。
while (false) {
console.log('while文 実行') // 何も出力されない
}
do {
console.log('do...while文 実行') // 1度だけ出力される
} while (false)
どちらも条件はfalseとなっています。
while
は条件判定を前に行うため、ループ処理は実施されません。
do...while
は条件判定を後に行うため、1度処理を行った後で条件判定が行われます。
条件はfalseなので2度目の処理は実施されず終了します。
使い所
ユーザーからの入力を繰り返し受け取ったり、テキストファイルを読み込んで1行ずつ処理したりする際に使います。
これらはいずれも、どれくらいループを繰り返すか、がわかっていないループ処理になります。
let input;
do {
input = prompt('文字列を入力してください (qで終了):');
console.log(`入力された値: ${input}`);
} while (input !== 'q');
この場合は必ず1回目のpromptを実行させたいので、do...while
を使っています。
(ただし、while
を使っても同じものを書くことができます。)
どちらもほぼ挙動は同じ(1回目をやらない場合があるかどうかだけ違う)なので、どちらを使ってもよいと個人的には考えています。
for系
for
、for...in
、for...of
の3つがあります。
いずれも似ていますが、while
系と異なり明確に用途が違います。
for
初期値、終了条件、増分の値を決め、決められた終了条件を満たすまでループを実施します。
ループを実施したい回数が決まっているときに適しています。
for(初期値; 終了条件; 増分){
// 何らかの処理
}
for...in
オブジェクトのプロパティをループ処理します。
オブジェクト内のすべてのプロパティに対して処理を行いたいときに適しています。
for(変数 in オブジェクト){
}
for...of
繰り返し可能なオブジェクトをループ処理します。
繰り返し可能なオブジェクトとしては配列、String、Map、Setなどがありますが、主に配列に対して繰り返し処理を行いたいときに適しています。
for(変数 of オブジェクト){
}
3つの違いと使い所
whileはちょっとした違いだけでしたが、for系はその処理が明確に異なっています。
例えば、1から10まで処理を繰り返したい場合にはfor
しか使えません。
決められた回数ループ処理をするための構文です。
for (let i = 1; i <= 10; i++) {
// 平方数を求める
console.log(i * i);
}
for...in
はオブジェクトのプロパティを取得するので、その用途はかなり限定的です。
const obj = { name: 'Taro', age: 24, country: 'Japan' };
for (const o in obj) {
console.log(o);
// name
// age
// country
// と出力される
}
オブジェクトの中身を一気に書き換えたいときとかには使えるかもしれません。
const obj = { name: 'Taro', age: 24, country: 'Japan' };
for (const o in obj) {
// プロパティ名から値を取得
const val = obj[o];
// プロパティ名を指定して、新たな値を設定
obj[o] = 'new' + val;
}
console.log(obj);
// {name: 'newTaro', age: 'new24', country: 'newJapan'}
// と出力される
配列をループ処理する場合、基本的にはfor...of
を使います。
const arr = ['hoge', 'piyo', 'bar'];
for (let a of arr) {
console.log(a)
// hoge
// piyo
// bar
// と出力される
}
for
を使って配列のループをすることもできますが、複雑になるのとエラーの原因になることもあるので、for...of
が基本的にはおすすめです。
どうしてもインデックスを使いたい、という場合にはfor
でもいいでしょう。
const arr = ['hoge', 'piyo', 'bar'];
// forの()内がfor...ofより複雑
for (let i = 0; i <= arr.length; i++) {
// 本当はi < arr.lengthにしなければならない
// エラーになる可能性がある例としてわざと間違えている
console.log(arr[i]);
// hoge
// piyo
// bar
// undefined
// と出力される
// →undefinedになるのは配列に存在しない要素にアクセスしているため
// エラーの原因になる可能性
}
また、配列に対してfor...in
を使っても、値は取得できないので注意。
※for...in
はプロパティを取得する
const arr = ['hoge', 'piyo', 'bar'];
// forの()内がfor...ofより複雑
for (let a in arr) {
console.log(a);
// 0
// 1
// 2
// と出力される
}
配列も実はオブジェクト。
プロパティが自動で0から順に1ずつ数値が増える形でプロパティが定義されたオブジェクトになっているので、上記のようになる。
まとめ
while系のループと、for系のループについて確認しました。
個人的にfor...in
とfor...of
の使い分けが微妙に理解できていなかったので、これを期に完全にマスターできればと思っています。
また、for...in
とfor...of
の本質的な違いとして、列挙可能プロパティと反復可能プロパティというキーワードがあるのですが、この点についてはまた別の機会で触れようかと思います。