JavaScriptのループ設計：for / forEach / map / reduce / for...of すべての使いどころを言語化する


## 概要

ループは、プログラミングにおける最も基本的な制御構文だ。  
しかしJavaScriptでは、ループの手段が多すぎる。

- `for`
- `forEach`
- `map`
- `reduce`
- `for...of`
- `for...in`

「なんとなく使ってる」では、バグ・非効率・可読性の劣化を招く。  
この記事では、それぞれのループ構文の**構文的な違いと使い分けの判断軸**を、**設計目線で整理**していく。

---

## 対象環境

```text
ES6以降のJavaScript（Node.js / ブラウザ）
```

---

## 各ループ構文の特徴と選定基準

| 構文        | 主な用途               | 副作用あり | return値     | 中断可       | イテラブル対応 | 適しているケース                        |
|-------------|------------------------|------------|--------------|--------------|----------------|-----------------------------------------|
| `for`       | 汎用                   | ✅          | ❌ undefined | ✅ `break`可 | ✅              | 制御フローが複雑 / 索引アクセスが必要 |
| `forEach`   | 配列の処理             | ✅          | ❌ undefined | ❌不可       | ✅              | 単純な副作用処理                       |
| `map`       | 配列を変換して返す     | ❌推奨外    | ✅ 配列      | ❌不可       | ✅              | 配列変換ロジック                       |
| `reduce`    | 配列を単一値に畳み込む | ❌推奨外    | ✅ 任意値    | ❌不可       | ✅              | 集計・合計・構造変換                   |
| `for...of`  | 任意のイテラブル処理   | ✅          | ❌ undefined | ✅ `break`可 | ✅              | 配列 / Set / Map の繰り返し処理       |
| `for...in`  | オブジェクト列挙       | ✅          | ❌ undefined | ✅ `break`可 | ❌              | キー列挙のみ。配列には不向き           |

---

## それぞれの実例と解説

### 1. `for`

```js
for (let i = 0; i < items.length; i++) {
  console.log(items[i]);
}
```

- ✅ 高い柔軟性
- ❌ 長くなりがち
- ✅ 中断可能 (`break`, `continue`)

---

### 2. `forEach`

```js
items.forEach(item => {
  console.log(item);
});
```

- ✅ 簡潔
- ❌ `return`, `break` できない
- ❌ チェーン不可（return値なし）

---

### 3. `map`

```js
const doubled = items.map(x => x * 2);
```

- ✅ 「変換」に強い（1対1の変換）
- ❌ 副作用は禁止
- ✅ チェーン可能

---

### 4. `reduce`

```js
const total = items.reduce((acc, cur) => acc + cur, 0);
```

- ✅ 単一値の集約に最適
- ✅ 初期値を使って安全に設計可能
- ❌ 初見では読みにくいことも

---

### 5. `for...of`

```js
for (const item of items) {
  console.log(item);
}
```

- ✅ シンプルで安全
- ✅ break / continue / return 可能
- ✅ 配列 / Set / Map / arguments に対応

---

### 6. `for...in`

```js
for (const key in obj) {
  console.log(`${key}: ${obj[key]}`);
}
```

- ✅ オブジェクトのキー列挙に適している
- ❌ 配列に使うとインデックス順が保証されない
- ❌ プロトタイプ継承の影響を受ける

→ ✅ `Object.hasOwn()` との併用が安全：

```js
for (const key in obj) {
  if (Object.hasOwn(obj, key)) {
    // ...
  }
}
```

---

## ループ選定の設計思考

| 目的                           | 推奨構文     |
|--------------------------------|--------------|
| 配列を変換したい               | `map`        |
| 累積して1つの値を導出したい    | `reduce`     |
| 副作用処理（API呼び出しなど） | `forEach`    |
| breakしたい                    | `for`, `for...of` |
| イテラブル全般を処理したい    | `for...of`   |
| オブジェクトのキーを走査      | `for...in`（+ hasOwn） |

---

## よくある誤用

### ❌ `map` を副作用目的で使う

```js
items.map(item => console.log(item)); // ❌ 非推奨
```

→ ✅ `forEach` もしくは `for...of` を使うべき

---

### ❌ `for...in` を配列に使う

```js
for (const i in arr) {
  console.log(arr[i]); // ❌ インデックス順を保証しない
}
```

→ ✅ `for`, `for...of` が適切

---

### ❌ `forEach` で早期リターンしようとする

```js
items.forEach(item => {
  if (item > 10) return; // ❌ これは次のループをスキップしない
});
```

→ ✅ `for` / `for...of` に置き換える

---

## 結語

ループ処理とは、単なる反復ではない。  
**意図を明示するための制御構造であり、責任の分岐点でもある。**

すべてのループ構文には、それが設計された理由がある。  
その意図を汲み取り、**機能だけでなく意味を持った選定**を行うこと。

コードの動作を決めるのは構文だが、  
コードの価値を決めるのは設計である。