JavaScriptで繰り返し処理書くたびにググるのを卒業しよう

## はじめに
JavaScriptで配列やオブジェクトの繰り返し処理を書くときに、いつもググっていませんか？
`for...in`なのか、`for...of`なのか
はたまた`for`を使うか、`while`を使うのか
わたしはググっていました。

`for`と`while`ならわかりますが、`for...in`と`for...of`がいつもふわっとしています。

しっかり基礎をおさえて、繰り返し処理のググりとおさらばします。

## while系
`while`と`do...while`があります。
どちらもループ処理を実施する回数が決まっていない場合に適しています。

### while
ループを実施するための条件判定を、処理の**実施前**に行います。
条件の内容によっては、一度もループをしないこともあります。
```javascript:while文
while (条件式) {
  // 何らかの処理
}
```

### do...while
ループを実施するための条件判定を、処理の**実施後**に行います。
どんな条件であっても、必ず1度は処理を実施します。
```javascript:do...while文
do {
  // 何らかの処理
} while(条件式)
```

### 2つの違い
`while`と`do...while`はどちらも条件式がtrueである間、ずっと繰り返し処理を実施します。
大きな違いは、条件判定を前にするか、後にするか、です。
以下のコードは、その違いが顕著にあらわれています。
```javascript:2つの比較
while (false) {
    console.log('while文 実行') // 何も出力されない
}

do {
    console.log('do...while文 実行') // 1度だけ出力される
} while (false)
```

どちらも条件はfalseとなっています。
`while`は条件判定を前に行うため、ループ処理は実施されません。
`do...while`は条件判定を後に行うため、1度処理を行った後で条件判定が行われます。
条件はfalseなので2度目の処理は実施されず終了します。

### 使い所
ユーザーからの入力を繰り返し受け取ったり、テキストファイルを読み込んで1行ずつ処理したりする際に使います。
これらはいずれも、どれくらいループを繰り返すか、がわかっていないループ処理になります。

```javascript:ユーザーからの入力を繰り返し受け取る例
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
初期値、終了条件、増分の値を決め、決められた終了条件を満たすまでループを実施します。
ループを実施したい回数が決まっているときに適しています。
```javascript:for文
for(初期値; 終了条件; 増分){
 // 何らかの処理
}
```

### for...in
オブジェクトのプロパティをループ処理します。
オブジェクト内のすべてのプロパティに対して処理を行いたいときに適しています。
```javascript:for...in文
for(変数 in オブジェクト){
}
```

### for...of
繰り返し可能なオブジェクトをループ処理します。
繰り返し可能なオブジェクトとしては配列、String、Map、Setなどがありますが、主に配列に対して繰り返し処理を行いたいときに適しています。
```javascript:for...of文
for(変数 of オブジェクト){
}
```

### 3つの違いと使い所
whileはちょっとした違いだけでしたが、for系はその処理が明確に異なっています。

例えば、1から10まで処理を繰り返したい場合には`for`しか使えません。
決められた回数ループ処理をするための構文です。
```javascript:1から10まで繰り返し
for (let i = 1; i <= 10; i++) {
    // 平方数を求める
    console.log(i * i);
}
```

`for...in`はオブジェクトのプロパティを取得するので、その用途はかなり限定的です。
```javascript:オブジェクトのプロパティを取得
const obj = { name: 'Taro', age: 24, country: 'Japan' };
for (const o in obj) {
    console.log(o);
    // name
    // age
    // country
    // と出力される
}
```

オブジェクトの中身を一気に書き換えたいときとかには使えるかもしれません。
```javascript:オブジェクトの中身を一気に書き換え
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`を使います。
```javascript:配列をループ処理
const arr = ['hoge', 'piyo', 'bar'];
for (let a of arr) {
    console.log(a)
    // hoge
    // piyo
    // bar
    // と出力される
}
```

`for`を使って配列のループをすることもできますが、複雑になるのとエラーの原因になることもあるので、`for...of`が基本的にはおすすめです。
どうしてもインデックスを使いたい、という場合には`for`でもいいでしょう。
```javascript: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`はプロパティを取得する
```javascript:forをつかった配列のループ
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`の本質的な違いとして、列挙可能プロパティと反復可能プロパティというキーワードがあるのですが、この点についてはまた別の機会で触れようかと思います。