JavaScript | 配列・オブジェクト:オブジェクト操作 – for…in

JavaScript JavaScript
スポンサーリンク

for…in とは何か

for…in は「オブジェクトの“列挙可能なキー(プロパティ名)”を1つずつ取り出して処理する」ためのループ構文です。ここが重要です:for…in は“自分のキーだけ”ではなく“継承(プロトタイプ)上のキー”も回り得ます。初心者はこの挙動を理解し、必要に応じて所有判定(Object.hasOwn)を組み合わせて使うのが安全です。

const user = { id: 1, name: "Alice" };
for (const key in user) {
  console.log(key, user[key]); // id 1 / name Alice
}
JavaScript

何が回るのか(対象と除外のルール)

列挙対象の基本ルール

for…in が回すのは「列挙可能(enumerable: true)の文字列キー」です。オブジェクトリテラルで定義した通常のプロパティは列挙対象になります。一方、Symbol キーは回りません。Object.defineProperty で enumerable: false にしたプロパティも回りません。

const k = Symbol("secret");
const obj = {};
Object.defineProperty(obj, "hidden", { value: 1, enumerable: false });
obj[k] = 123;
obj.visible = 2;

for (const key in obj) {
  console.log(key); // visible だけ
}
JavaScript

継承(プロトタイプ)上のキーも回る

オブジェクト自身にないキーでも、プロトタイプにある列挙可能なキーは for…in に出てきます。これが混入すると意図しない処理につながります。

const base = { kind: "person" }; // 列挙可能
const obj = Object.create(base);
obj.name = "Alice";

for (const key in obj) {
  console.log(key); // name, kind(継承も回る)
}
JavaScript

安全に使うための所有判定(ここが重要)

Object.hasOwn で“自分のキーだけ”に絞る

継承キーを除外したいときは、ループ内で所有判定を入れます。ES2022 以降は Object.hasOwn が読みやすく安全です。

const base = { kind: "person" };
const obj = Object.create(base);
obj.name = "Alice";

for (const key in obj) {
  if (!Object.hasOwn(obj, key)) continue; // 継承キーはスキップ
  console.log(key, obj[key]); // 自前のキーだけ処理
}
JavaScript

古い環境では hasOwnProperty.call を使う

対象が hasOwnProperty を上書きしていても確実に判定できます。

for (const key in obj) {
  if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;
  // 自前のキーだけ
}
JavaScript

配列と for…in の関係(誤用を避ける)

配列には基本使わない

配列の要素走査は for…of、for、map、forEach が適切です。for…in は数値インデックスだけでなく追加した自前プロパティも回る可能性があり、順序保証も弱く、意図が伝わりづらくなります。

const arr = ["A", "B"];
arr.extra = 999;

// NG: 予期せぬキーまで回る可能性
for (const key in arr) {
  console.log(key); // "0","1","extra" など
}

// OK: 要素だけ回る
for (const v of arr) console.log(v); // "A","B"
JavaScript

疎配列の“穴”の扱いに注意

for…in は“存在するインデックスキー”だけを回し、穴(空スロット)は回りません。挙動差を理解して構文を選びましょう。

const arr = [];
arr[2] = "X"; // [ <2 empty items>, "X" ]

for (const i in arr) {
  console.log(i, arr[i]); // "2" "X"(穴は回らない)
}
JavaScript

実務での使いどころと代替(可読性を高める選択)

オブジェクトの全キーをざっと処理したいとき

所有判定を入れた上で、キーと値を処理します。整形や送信前のフィルタに向きます。

function sanitize(obj) {
  const out = {};
  for (const key in obj) {
    if (!Object.hasOwn(obj, key)) continue;
    const v = obj[key];
    if (v != null) out[key] = v; // null/undefined を除外
  }
  return out;
}
JavaScript

可読性重視なら Object.entries を優先

キーと値を同時に扱うなら Object.entries → for…of の方が意図が明確になります。所有判定は不要(自前のキーだけが返る)です。

const user = { id: 1, name: "Alice" };
for (const [k, v] of Object.entries(user)) {
  console.log(`${k}=${v}`);
}
JavaScript

キーだけ必要なら Object.keys

キー配列を取得して、for…of で処理します。継承は含まれず安全です。

for (const k of Object.keys(user)) {
  console.log(k, user[k]);
}
JavaScript

よくある落とし穴と回避策(重要ポイントの深掘り)

予期せぬ継承キーが混ざる

ライブラリやフレームワークがプロトタイプへユーティリティを追加していると、for…in に出てきます。必ず所有判定で守りましょう。

non-enumerable と Symbol が回らないことを見落とす

設定や内部フラグを non-enumerable や Symbol で持っている場合、for…in では列挙されません。必要なら Object.getOwnPropertyNames/Object.getOwnPropertySymbols を使って取得します。

null/undefined の対象で例外

for…in の右辺が null/undefined だとエラーになります。外部入力やネストでは事前ガードを入れてください。

function safeForIn(obj) {
  if (obj == null || typeof obj !== "object") return;
  for (const k in obj) { /* ... */ }
}
JavaScript

配列の順序・要素処理に使ってしまう

配列は順序が重要です。for…in は順序保証が弱く、追加したカスタムプロパティも回るため不適切です。for…of/標準メソッドを使うのが原則です。


まとめ

for…in は「オブジェクトの列挙可能な文字列キー」を回すための構文で、継承キーも含み得るのが最大の特徴です。安全に使うには、ループ内で Object.hasOwn(または hasOwnProperty.call)による所有判定を必ず入れます。配列の走査には不適で、キーと値の整形には Object.entries、キーだけなら Object.keys のほうが可読性と安全性が高い。non-enumerable・Symbol・null/undefined の扱いを理解し、目的に合う構文へ置き換えることで、初心者でも意図どおりで壊れにくいループ設計ができます。

タイトルとURLをコピーしました