0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2025-04-03

記事作成のきっかけ

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

【for...inループ】

概要

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

特徴

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

実装例

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ループの利用について

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

【for...ofループ】

概要

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

特徴

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

実装例

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で終了します
}
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ループの利用について

オブジェクト型での利用について
下記のようにオブジェクトをそのままfor...ofループで
反復処理を行うことは出来ません。

// オブジェクト型ではfor...ofループの使用不可
const user = {
  name: '山田太郎',
  age: 30,
  email: 'yamada@example.com'
};

オブジェクトの配列で利用することは可能

// 配列であればオブジェクト型で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メソッド】

概要

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

特徴

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

実装例

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関数】

概要

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

特徴

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

実装例

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を使うことで、データ配列と表示要素の関係を直接的に宣言出来る
mapSample1.tsx
{items.map(item => (
  <Text key={item.id}>{item.name}</Text>
))}
  • mapは元の配列を変更せず、
    新しい要素の配列(reactではJSX要素)を生成するため、
    Reactの「状態は直接変更せず、新しい値を生成する」という
    原則に合致する

  • Reactでリスト要素を表示する際は、
    各要素に一意のkeyプロパティを与える必要があり、
    mapはインデックスや要素のIDを使って
    簡単にキーを割り当てられる
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応答の整形
  • 表示用データの準備
  • 計算や値の変換

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

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?