JavaScriptのプログラムを書く際、配列やオブジェクトの要素を順番に処理する「ループ処理」は欠かせない要素です。
特に、名前が似ているfor...in文とfor...of文の使い分けに悩む開発者は少なくありません。
一見するとどちらも同じように繰り返し処理を行っているように見えますが、その内部的な挙動や対象となるデータ構造には決定的な違いがあります。
2026年現在のモダンなフロントエンド開発においても、これらの基礎を正しく理解しておくことは、バグの少ないクリーンなコードを書くために非常に重要です。
本記事では、これら2つの構文の違いを明確にし、どのようなシーンでどちらを使うべきかを実例を交えて詳しく解説していきます。
JavaScriptにおけるループ処理の基本
JavaScriptには多様な繰り返し構文が存在しますが、その中でもfor...inとfor...ofは、ES6(ECMAScript 2015)以降、特によく使われるようになりました。
以前は伝統的なfor(let i = 0; i < array.length; i++)という書き方が主流でしたが、現在はより簡潔に記述できるこれらの構文が好まれています。
しかし、対象が「オブジェクト」なのか「配列」なのか、あるいは「取得したいのはキーなのか値なのか」によって、選択すべき構文は明確に決まっています。
この選択を誤ると、予期せぬプロトタイプのプロパティを取得してしまったり、実行速度が低下したりする原因となります。
for…in文:プロパティ名を列挙する
for...in文は、オブジェクトの「列挙可能なプロパティ(キー名)」をループ処理するために設計されています。
オブジェクト内のすべてのキーを一つずつ取り出し、そのキーに対して何らかの処理を行いたい場合に最適です。
オブジェクトでの基本的な使い方
まずは、一般的なオブジェクトに対してfor...inを使用した例を見てみましょう。
const user = {
name: "田中太郎",
age: 28,
role: "Developer"
};
for (const key in user) {
// keyにはプロパティ名が入る
console.log(`キー: ${key}, 値: ${user[key]}`);
}
キー: name, 値: 田中太郎
キー: age, 値: 28
キー: role, 値: Developer
このように、for...inを使うとオブジェクトのプロパティ名を順番に取得できることがわかります。
このとき、変数のkeyには文字列としてプロパティ名が代入される点に注目してください。
for…inの注意点:プロトタイプチェーン
for...inを使用する際に最も注意すべき点は、オブジェクト自身のプロパティだけでなく、継承されたプロパティも列挙対象になるという点です。
意図しない動作を防ぐためには、Object.hasOwn()メソッドなどを使用して、そのオブジェクト自身のプロパティであるかを確認する必要があります。
// 親オブジェクト
const person = {
species: "Human"
};
// personを継承したchildオブジェクト
const child = Object.create(person);
child.name = "健太";
for (const key in child) {
console.log(key); // "name"だけでなく、継承された"species"も表示される
}
name
species
このように、期待していた以上のデータが取得されるリスクがあるため、配列に対してfor...inを使用することは推奨されません。
for…of文:反復可能なオブジェクトの値を処理する
一方、for...of文は、ES6で導入された比較的新しい構文であり、「反復可能(Iterable)なオブジェクトの値」を直接取り出すために使用されます。
主に配列(Array)、文字列(String)、Map、Set、NodeListなどのコレクションを扱う際に非常に便利です。
配列での基本的な使い方
配列の要素を順番に処理する場合、for...ofが最も標準的な選択肢となります。
const colors = ["Red", "Green", "Blue"];
for (const color of colors) {
// colorには要素の値が直接入る
console.log(color);
}
Red
Green
Blue
for...inとは異なり、インデックス番号ではなく「中身の値」を直接取得できるため、コードが非常にシンプルになります。
その他の反復可能オブジェクトへの利用
for...ofは配列以外にも、多様なデータ構造に対応しています。
例えば、文字列を1文字ずつ処理したり、Mapオブジェクトのエントリを取得したりすることが可能です。
// 文字列のループ
const text = "JS2026";
for (const char of text) {
console.log(char);
}
// Mapのループ
const userRoles = new Map([
["admin", "管理者"],
["editor", "編集者"]
]);
for (const [role, label] of userRoles) {
console.log(`${role}は${label}です`);
}
J
S
2
0
2
6
adminは管理者です
editorは編集者です
このように、for...ofは「データの集まり」を扱う際に一貫したインターフェースを提供してくれます。
for…in と for…of の決定的な違い
ここでは、両者の違いをさらに深掘りし、比較表を用いて整理します。
最も大きな違いは、「何を対象にループを回すか」と「何を取得するか」の2点に集約されます。
比較表:特性の違い
| 特徴 | for…in | for…of |
|---|---|---|
| 主な対象 | オブジェクト(連想配列) | 配列、反復可能オブジェクト |
| 取得できるもの | プロパティ名(キー) | 要素の値(バリュー) |
| 継承プロパティ | 対象に含む(列挙可能なら) | 対象外 |
| 配列での利用 | 非推奨(意図しない動作の可能性) | 推奨 |
配列に for…in を使うのがNGな理由
JavaScriptの配列は、実体としては特殊な「オブジェクト」です。
そのため、配列に対してfor...inを使用することも技術的には可能ですが、2つの大きなデメリットがあります。
1つ目は、インデックスが「数値」ではなく「文字列」として取得されるため、数値計算にそのまま使うとバグの原因になることです。
2つ目は、配列のカスタムプロパティやArray.prototypeに追加された拡張機能までループで拾ってしまうリスクがあることです。
const arr = [10, 20, 30];
// 意図しないプロパティ追加(アンチパターン)
Array.prototype.customMethod = function() {};
for (const index in arr) {
console.log(index); // "0", "1", "2", "customMethod" が出力されてしまう
}
このような挙動を避けるためにも、配列のループ処理には必ずfor...ofを使用するようにしましょう。
実戦的な使い分けのパターン
2026年現在の開発現場では、単純なループ以外にも高度なデータ変換が求められます。
ここでは、より実践的なシーンでの使い分けテクニックを紹介します。
オブジェクトを for…of で処理する方法
通常、オブジェクトは反復可能ではないため、そのままではfor...ofを使うことができません。
しかし、Object.keys()、Object.values()、あるいはObject.entries()を併用することで、オブジェクトに対しても安全にfor...ofを適用できます。
const inventory = {
apples: 5,
oranges: 10,
bananas: 8
};
// Object.entriesを使って、キーと値を同時に取得する
for (const [item, count] of Object.entries(inventory)) {
console.log(`${item}の在庫は${count}個です`);
}
この手法は、for...inの持つ「継承プロパティを拾ってしまう」というデメリットを回避しつつ、オブジェクトの値を簡潔に扱うためのモダンなベストプラクティスです。
非同期処理での for…of の活用
配列の各要素に対して、非同期処理(APIリクエストなど)を順番に行いたい場合、for...ofは非常に強力な味方になります。
forEachメソッドの中ではawaitが期待通りに動作しませんが、for...ofブロック内であれば直列的な非同期処理が可能です。
const urls = ["/api/v1/user", "/api/v1/posts", "/api/v1/comments"];
async function fetchData(urlList) {
for (const url of urlList) {
const response = await fetch(url);
const data = await response.json();
console.log(`${url}のデータを取得完了`, data);
}
}
このように、for...ofは現代のJavaScript開発において、同期・非同期を問わず「値の集合」を安全に制御するための標準的なツールとなっています。
パフォーマンスと最適化の視点
大規模なデータを扱う場合、ループのパフォーマンスが気になることもあるでしょう。
一般的に、for...inはオブジェクトのプロパティをスキャンし、プロトタイプチェーンまで辿るため、処理速度は他のループ構文に比べて低速になる傾向があります。
一方、for...ofはイテレータプロトコルに基づいているため、現代のブラウザのJavaScriptエンジン(V8など)で高度に最適化されています。
数万件規模のデータをループさせる場合は、for...ofや、さらにプリミティブなfor文を検討するのが賢明です。
Map・Set と for…of の相性
2026年のJavaScriptでは、データの重複を防ぐためのSetや、順序を保持するMapの利用頻度が非常に高まっています。
これらのコレクションは、最初から「反復可能」な設計となっているため、for...ofとの相性が抜群です。
const uniqueIds = new Set([101, 102, 103, 101]);
for (const id of uniqueIds) {
console.log(`処理中のID: ${id}`);
}
for...inではこれらのコレクションを正しく扱うことができないため、データ構造に応じた適切な構文選択がコードの品質を左右します。
まとめ
JavaScriptのfor...inとfor...ofは、名前こそ似ていますが、その役割は明確に異なります。
「オブジェクトのキーを調べたいときは for…in」を、「配列やコレクションの値を処理したいときは for…of」を選択するのが基本の鉄則です。
特に配列に対してfor...inを使用することは、予期せぬ挙動やパフォーマンス低下を招くため、避けるべき習慣と言えます。
また、オブジェクトをループさせたい場合も、最近ではObject.entries()とfor...ofを組み合わせる手法が主流になっています。
それぞれの構文が持つ特性と注意点を正しく理解し、2026年のスタンダードにふさわしい、読みやすく保守性の高いコードを目指しましょう。
この記事が、皆さんのJavaScriptコーディングにおける迷いを解消する一助となれば幸いです。
