【Javascript】繰り返し処理の整理

## 記事作成のきっかけ
Javascriptには様々な繰り返しの構文やメソッドがあり、
卒業制作で利用した繰り返しの構文、
メソッドについて整理をしたいと思い、
記事作成を行おうと思いました。

## 【for...inループ】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for...in

#### 概要
オブジェクトのプロパティを列挙するためのループ構文

#### 特徴
- オブジェクトの列挙可能なプロパティを全て反復処理をする
（truthyな値を保持するオブジェクトが全て）
- プロトタイプチェーンを上るので、継承されたプロパティも含まれる
（Object.prototype.xxxx = "不要なプロパティ"
　も反復対象に含まれる）
- プロパティの処理順序で保証されない場合がある
- 配列に使用すると、インデックスが文字列として取得される

#### 実装例
```javascript:forInSample.js
const obj = { a: 1, b: 2 };
Object.prototype.extraProp = "不要なプロパティ";

for (const key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key); // "a", "b"のみ出力（extraPropは出力されない）
  }
}
```
Object.prototype.extraProp = "不要なプロパティ"
も反復処理の対象として含まれるため、
意図しないプロパティまで反復対象としてループ処理を処理されてしまいます。
対策としては、**hasOwnProperty**を使用し、
継承プロパティを除外する処理を追加する必要がある。

#### 想定する利用シーン
- 動的なプロパティ名を持つオブジェクトの処理
- 設定オブジェクトのすべてのキーにアクセスする必要がある場合
- オブジェクトのシリアライズ/デシリアライズ処理
- オブジェクトのバリデーションや内容の検査

#### for...inループの利用について
:::note warn
for...inループの代替手段
一般的には、for...inループを使わず代替手段として、
forループ・forEach()、for...ofループを使うことが
一般的な反復処理として使うように
MDNでも推奨されています。
:::

## 【for...ofループ】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for...of

#### 概要
イテラブル（反復可能）オブジェクトの値を
順番に処理するループ構文

#### 特徴
- 配列、文字列、Map、Set、TypedArray、Generatorなど
イテラブルオブジェクトと互換性がある
- 値自体を直接取得できるため、配列処理が直感的
- async/awaitと組み合わせて非同期イテレーションが可能
- 処理の途中でbreak/continue/returnによる制御が可能

#### 実装例
```javascript:forOfSample1.js
// 制御構文との組み合わせ
const numbers = [1, 2, 3, 4, 5];

for (const num of numbers) {
  if (num === 2) {
    console.log('2をスキップします');
    continue;
  }
  
  if (num === 4) {
    console.log('4で終了します');
    break;
  }

  console.log(num);
  // コンソール出力結果
  // 1
  // 2をスキップします
  // 3
  // 4で終了します
}
```
```javascript:forOfSample2.js
// Mapの処理
const userMap = new Map([
  ['id1', { name: '田中', age: 28 }],
  ['id2', { name: '佐藤', age: 32 }],
  ['id3', { name: '鈴木', age: 24 }]
]);

for (const [id, user] of userMap) {
  console.log(`ID: ${id}, 名前: ${user.name}, 年齢: ${user.age}`);
  // コンソール出力結果
  // ID: id1, 名前: 田中, 年齢: 28
  // ID: id2, 名前: 佐藤, 年齢: 32
  // ID: id3, 名前: 鈴木, 年齢: 24
}
```
#### 想定する利用シーン
- 配列の要素を順番に処理する必要がある場合
- 処理の途中で条件に基づいて中断したい場合
- 非同期処理のシーケンシャルな実行
- ジェネレータ関数からデータを取得する場合
- MapやSetなどの特殊なコレクションの処理

#### for...ofループの利用について
:::note info
オブジェクト型での利用について
下記のようにオブジェクトをそのままfor...ofループで
反復処理を行うことは出来ません。
``` javascript:
// オブジェクト型ではfor...ofループの使用不可
const user = {
  name: '山田太郎',
  age: 30,
  email: 'yamada@example.com'
};
```
オブジェクトの配列で利用することは可能
``` javascript:
// 配列であればオブジェクト型でfor...ofループの使用不可
onst userArray = [
  { id: 'id1', name: '田中', age: 28 },
  { id: 'id2', name: '佐藤', age: 32 },
  { id: 'id3', name: '鈴木', age: 24 }
];

// for...ofループでユーザー配列を繰り返し処理
for (const user of userArray) {
  console.log(`ID: ${user.id}, 名前: ${user.name}, 年齢: ${user.age}`);
}
```
:::

## 【forEachメソッド】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

#### 概要
配列の各要素に対して関数を一度ずつ実行するメソッド

#### 特徴
- 配列専用のメソッドで、コールバック関数を各要素に適用
- 要素、インデックス、配列全体の3つの引数をコールバックに渡せる
- 戻り値は常にundefinedで、チェーン不可
- 途中で中断する手段がなく（breakやcontinueが使えない）、
すべての要素を処理する
- 実行中にコールバック内で配列を変更すると、
予期しない動作になる可能性がある

#### 実装例
```javascript:forEachSample1.js
// オブジェクトの配列
const users = [
  { id: 1, name: '田中太郎', age: 25 },
  { id: 2, name: '鈴木花子', age: 30 },
  { id: 3, name: '佐藤次郎', age: 22 }
];

// オブジェクト配列に対してforEachを使用
users.forEach(user => {
  console.log(`ID: ${user.id}, 名前: ${user.name}, 年齢: ${user.age}`);

  // コンソール出力結果
  // ID: 1, 名前: 田中太郎, 年齢: 25
  // ID: 2, 名前: 鈴木花子, 年齢: 30
  // ID: 3, 名前: 佐藤次郎, 年齢: 22
});
```

#### 想定する利用シーン
- 配列の各要素に対して副作用のある操作を行う場合
（各要素に対して何かを実行する意図が明確になる）
- DOM要素の更新やUIの描画
- サーバーへのリクエストなど、要素ごとの操作
（fetchなどで複数のAPIエンドポイントに
リクエスト送信したいケース）
（順次リクエストしたい場合はfor...ofループを使う）
- 配列の処理順序が重要で、かつ中断の必要がない場合
（break、continueなどの制御が使えない）
- コードの読みやすさを優先する場合

## 【map関数】
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

#### 概要
mapは配列の各要素に関数を適用し、その結果からなる新しい配列を返すメソッド

#### 特徴
- 元の配列と同じ長さの新しい配列を返却する
- 元の配列は変更されません（非破壊的操作）
- 各要素の変換に使用します
- 関数型プログラミングパターンと相性が良いです
- 他の配列メソッド（filter、reduceなど）と組み合わせて使用可能

#### 実装例
```javascript:mapSample1.js
// オブジェクトの配列
const users = [
  { id: 1, firstName: '太郎', lastName: '田中' },
  { id: 2, firstName: '花子', lastName: '鈴木' },
  { id: 3, firstName: '次郎', lastName: '佐藤' }
];

// オブジェクト配列の変換
const formmattedUsers = users.map(user => ({
    id: user.id,
    fullName: `${user.lastName} ${user.firstName}`
}));

console.log(formmattedUsers);
  // コンソール出力結果
  // [
  //   { id: 1, fullName: 田中 太郎 }
  //   { id: 2, fullName: 鈴木 花子 }
  //   { id: 3, fullName: 佐藤 次郎 }
  // ]
```
#### 想定する利用シーン
- 配列から新しい配列を作成する必要がある場合
- データの変換またはフォーマット変更が必要な場合
- 複数のメソッドをチェーンして複雑なデータ処理を行う場合
- 非同期処理を複数並列で実行する場合（Promise.allと組み合わせ）
- 関数型プログラミングスタイルを採用している場合

#### Reactでのmap関数利用について

map関数は、Reactのコンポーネントレンダリングで
良く使われているのを目にします。
その理由として、
- JSX(TSX)の中でmapを使うことで、データ配列と表示要素の関係を直接的に宣言出来る
``` react:mapSample1.tsx
{items.map(item => (
  <Text key={item.id}>{item.name}</Text>
))}
```
- mapは元の配列を変更せず、
新しい要素の配列（reactではJSX要素）を生成するため、
Reactの「状態は直接変更せず、新しい値を生成する」という
原則に合致する
<br>

- Reactでリスト要素を表示する際は、
各要素に一意のkeyプロパティを与える必要があり、
mapはインデックスや要素のIDを使って
簡単にキーを割り当てられる
```react:mapSample1.tsx
{users.map((user, index) => (
  <UserCard key={user.id || index} user={user} />
))}
```
## 使い分けと比較
| 特徴 | for...in | for...of | forEach | map |
|------|---------|----------|---------|-----|
| 対象データ | オブジェクト | イテラブル | 配列 | 配列 |
| 取得するもの | プロパティ名 | 値 | 値 | 値 |
| 戻り値 | なし | なし | undefined | 新しい配列 |
| 中断可能か | はい (break/continue) | はい (break/continue) | いいえ | いいえ |
| 非同期処理 | サポートなし | サポート (await) | サポートなし | Promise.all と組み合わせ可能 |
| 変換処理 | 不向き | 不向き | 不向き | 最適 |
| 副作用処理 | 可能 | 可能 | 最適 | 不向き |

#### 実践的な使い分け
●for...in: オブジェクトのプロパティを列挙
  - 設定オブジェクトの処理
  - 動的なプロパティを持つオブジェクトの検査
  - JSONデータの探索

●for...of: 値に順次アクセス
  - 非同期処理の順次実行
  - 中断が必要な繰り返し処理
  - 複雑なイテラブルの処理（ジェネレータなど）

●forEach: 副作用を伴う処理
  - DOM要素の更新
  - ログ出力
  - サーバーへのリクエスト送信

●map: データ変換
  - API応答の整形
  - 表示用データの準備
  - 計算や値の変換

まだまだ理解度が浅いので、
こちらの振り返り記事を都度見直しながら、
繰り返し構文（メソッド）の理解度を深めて行きたいと思います。
もし不備な点などあればご指摘ください。