【ぼくのJavaScript備忘録】 forEach の使い方徹底解説

## 1. forEach とは？


`forEach` は、JavaScript の配列や `NodeList`、`Map`、`Set` などの反復可能なオブジェクトに対して、**各要素に対して繰り返し処理を実行** できるメソッドです。

> **ポイント**：通常の `for` ループと異なり、`forEach` を使うと **シンプルに記述** できますが、`break` や `return` でループを抜けることはできなくなります。

forEach を使用できるオブジェクトの例：

- **`Array`**（配列）
- **`NodeList`**（`querySelectorAll` の結果）
- **`Map`**（`キー`と`値のペア`を保持するデータ構造）
- **`Set`**（`重複のない値`を保持するデータ構造）
- **`TypedArray`**（型付き配列 `Uint8Array` など）
- **`Iterator`**（2023年以降に追加）

> Iterator.prototype.forEach は 2023 年以降に追加されたため、Iterator に対しても forEach を使用可能になりました。
>
>> 補記：prototype とはオブジェクトの継承機能であり、特定のオブジェクトに共通のメソッドを提供する仕組みです。
例えば、Array.prototype.forEach は配列専用の forEach メソッドであり、Iterator.prototype.forEach はイテレーター専用の forEach メソッドを指します。
この仕組みのおかげで、オブジェクトごとに個別に forEach を定義するのではなく、prototype を利用して共通の機能を提供できます。

---


## 2. `forEach` の基本構文

```javascript
array.forEach((要素, インデックス, 配列) => {
    // 繰り返し処理
});
```

- `要素`：現在の要素の値
- `インデックス`（省略可）：現在の要素のインデックス（0 から始まる）
- `配列`（省略可）：元の配列全体

## 3. `forEach` の基本的な使い方

### 例1：配列の各要素を表示

```javascript
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => {
    console.log(num);
});
//出力：
//1 2 3 4 5
```

### 例2：インデックスを含めて出力

```javascript
const fruits = ["りんご", "バナナ", "ぶどう"];
fruits.forEach((fruit, index) => {
    console.log(`${index}: ${fruit}`);
});
//出力：
//0: りんご
//1: バナナ
//2: ぶどう
```

## 4. `forEach` の活用

### `querySelectorAll` との併用

`querySelectorAll` は `NodeList` を返しますが、`forEach` を使ってループ処理が可能です。

```javascript
const items = document.querySelectorAll(".item");
items.forEach(item => {
    item.style.color = "red";
});
// すべての .item 要素の文字色を赤に変更
```

## 5. `forEach` と `for` ループの違い

| 比較項目         | `forEach`       | `for` ループ     |
| ------------ | --------------- | ------------- |
| 記述の簡潔さ       | ◎ 短く書ける         | △ やや長くなる      |
| ループの途中終了     | ✖ `break` できない  | ◎ `break` 可能  |
| `return` の扱い | ✖ `return` できない | ◎ `return` 可能 |

### 例3：`forEach` vs `for`

```javascript
const numbers = [1, 2, 3, 4, 5];

// forEach（ループを途中で抜けられない）
numbers.forEach(num => {
    if (num === 3) {
        return; // ループは止まらない（単なる関数のreturnで、ループには影響しない）
    }
    console.log(num);
});
// 出力：
// 1
// 2
// 4
// 5

// for ループ（break で終了可能）
for (let i = 0; i < numbers.length; i++) {
    if (numbers[i] === 3) {
        break; // ループ終了
    }
    console.log(numbers[i]);
}
// 出力：
// 1
// 2
```

## 6. `map` との違い

`forEach` と `map` は似ていますが、**`map`** は新しい配列を返す のに対し、**`forEach`** は配列を変更せずに処理を実行します。

```javascript
const numbers = [1, 2, 3, 4, 5];

// forEach（結果を返さない）
numbers.forEach(num => num * 2);
console.log(numbers); // [1, 2, 3, 4, 5]

// map（新しい配列を返す）
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
```

> データを変換したいなら **`map`**、処理を実行するだけなら **`forEach`**

## 7. `Iterator.prototype.forEach` の登場（2023年以降）

これまで `forEach` は `Array` や `NodeList` などに使われていましたが、**2023 年以降 **`Iterator`** にも **`forEach`** メソッドが追加** されました。

### `Iterator.prototype.forEach` の特徴

- **逐次取得** するため、**メモリ効率が良い**（全データをメモリに展開しない）
- **`Set.values()`** や **`Map.keys()`** などのイテレーターにも適用可能


コンソールで、
```javascript
console.log(Array.prototype);
```
や
```javascript
console.log(Iterator.prototype);
```
とすると、ArrayやIteratorが持っているメソッドを確認できる

---

## 8. Iterator（イテレーター）とは？

**Iterator**とは、データを1つずつ順番に取得できるオブジェクトです。
**.next()** メソッドを持ち、データを逐次取得する仕組みを提供します。

### **Iteratorの基本的な動作**

```javascript
const iterator = [1, 2, 3][Symbol.iterator]();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { done: true } // 処理が終了した合図
```

**Iterator** は **.next()** を使って順番に値を取得できる。

> **配列** や **Set** や **Map** はデフォルトで **Iterator** ではなく **Iterable**。 **Iterator** を取得するには **Symbol.iterator** を使う。
> あるいは、array.values() や set.values()、map.keys() を使うと Iterator を取得できる。

```javascript
const set = new Set(["a", "b", "c"]);
const iterator = set.values();
console.log(iterator.next()); // { value: "a", done: false }
```

### **Symbol.iterator を持つデータ型**

以下のデータ型は Symbol.iterator を持っており、Iterator を作成できます。

- **`Array`**（配列）
- **`String`**（文字列）
- **`Set`**（集合）
- **`Map`**（連想配列）
- **`arguments`**（関数の引数オブジェクト）
- **`NodeList`**（DOMの querySelectorAll などで取得されるリスト）
- **`TypedArray`**（Uint8Array や Float32Array などの型付き配列）

 **Symbol.iterator を持つか確認する方法**
```javascript
console.log(typeof Array.prototype[Symbol.iterator]);  // function
console.log(typeof String.prototype[Symbol.iterator]); // function
console.log(typeof Set.prototype[Symbol.iterator]);    // function
console.log(typeof Map.prototype[Symbol.iterator]);    // function
console.log(typeof arguments[Symbol.iterator]);        // function（関数の中で確認）
console.log(typeof NodeList.prototype[Symbol.iterator]); // function（`querySelectorAll` で取得した要素群）
```
 **これらのオブジェクトは Symbol.iterator を持っているため、for...of や Iterator.prototype.forEach を適用可能！**

---

## 9. Iterator.prototype.forEach

### ☑️ Iterator に forEach を使う

Iterator.prototype.forEach は、**Iteratorの `forEach` メソッド** であり、Iterator に対して forEach を適用することができます。

```javascript
const set = new Set(["apple", "banana", "cherry"]);

set.values().forEach(fruit => {
    console.log(fruit);
});
// 出力:
// apple
// banana
// cherry
```

**Set ではなく、Iterator に対して forEach を適用している！**
**逐次取得（1つずつ処理）するため、メモリ使用量を抑えられる！**

---
## 10. Iterator.prototype.forEach の対応状況

Iterator.prototype.forEach は 比較的新しい技術（2023年以降） であり、すべてのブラウザでサポートされているわけではありません。

対応状況を確認するサイト

 最新の対応状況は、以下のサイトで確認できます。

[Can I use](https://caniuse.com/mdn-javascript_builtins_iterator_foreach)

[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Iterator/forEach)

 Iterator.prototype.forEach を使用する際は、古いブラウザでの動作に注意が必要です！

---


## 11. まとめ

☑️ `forEach` は配列や `NodeList` に対して **繰り返し処理** を適用できる\
☑️ `for` ループよりも **簡潔に書けるが、途中終了は不可**\
☑️ `querySelectorAll` の `NodeList` に対しても利用可能\
☑️ `map` との違いを理解し、適切に使い分ける\
☑️ 2023 年以降 **`Iterator.prototype.forEach`** が追加され、**`Iterator`** にも **`forEach`** を適用できるようになった
☑️ **`Iterator.prototype.forEach`** はストリーム処理など、大量データを扱う場面で特に有効
☑️ **Iterator.prototype.forEach は比較的新しい技術であり、古いブラウザでは対応していない可能性があるため注意！**

`forEach` を適切に活用し、**効率的なループ処理を実装しよう！**