プロパティの存在チェック(’prop’ in obj)の基本と実践
「そのプロパティある?」を最短で判定するのが in 演算子。自前のプロパティだけでなく、プロトタイプから継承されたプロパティも「存在する」と判定します。
基本の挙動と書き方
const user = { name: "Aki", age: 22 };
console.log("name" in user); // true
console.log("address" in user); // false
JavaScript- 判定対象: オブジェクト自身+プロトタイプチェーン上の列挙/非列挙プロパティも含めて「名前があるか」を判定。
- 戻り値: true/false のブール値。
- 注意: 値が
undefinedでも「プロパティが存在すれば」true。
const obj = { key: undefined };
console.log("key" in obj); // true(存在する)
console.log(obj.key !== undefined); // false(値は未定義)
JavaScriptすぐ使えるテンプレート集
継承プロパティも含めて存在確認(in)
const obj = {};
console.log("toString" in obj); // true(Object.prototype由来)
JavaScript- ポイント: 「とにかく名前があるか」を見たいときは
inがラク。
自前プロパティだけ確認(Object.hasOwn)
const obj = Object.create({ inherited: 1 });
obj.own = 2;
console.log(Object.hasOwn(obj, "own")); // true
console.log(Object.hasOwn(obj, "inherited")); // false
JavaScript- ポイント: 継承を含めたくないなら
Object.hasOwn(obj, key)が明快。
古典的な自前判定(hasOwnProperty)
const obj = { a: 1 };
console.log(obj.hasOwnProperty("a")); // true
JavaScript- ポイント: 既存コードでよく見る。安全に使うなら
Object.prototype.hasOwnProperty.call(obj, key)。
値が設定済みかを確認(存在+未定義の区別)
const payload = { id: 0, name: "" }; // falsyでも“値はある”
console.log("id" in payload); // true
console.log(payload.id !== undefined); // true
console.log(Boolean(payload.id)); // false(値は0 = falsy)
JavaScript- ポイント: 「キーの存在」「未定義でない」「truthy/falsey」は別概念。
安全アクセス(Optional chaining)
const obj = { user: { profile: { city: "Tokyo" } } };
console.log(obj.user?.profile?.city ?? "N/A"); // "Tokyo"
console.log(obj.admin?.profile?.city ?? "N/A"); // "N/A"
JavaScript- ポイント: 存在チェックとアクセスを一度に。落ちずに安全。
実務での使い分け
- プロパティ名がオブジェクトに“どこか”にあればOK:
- おすすめ:
'key' in obj
- おすすめ:
- 自前のキーだけか知りたい(継承除外):
- おすすめ:
Object.hasOwn(obj, 'key')
- おすすめ:
- 値が設定されているか(未定義でないか):
- おすすめ:
obj.key !== undefined
- おすすめ:
- ネストアクセスを安全に:
- おすすめ:
obj?.nested?.keyと??でデフォルト付与
- おすすめ:
よくある落とし穴と対策
- undefinedと「不存在」を混同: 値がundefinedでもキーがあれば
inはtrue。- 対策: キーの有無は
in/自前判定はObject.hasOwn/値確認は!== undefinedを使い分け。
- 対策: キーの有無は
- 配列で値の存在を
inで調べる誤用:inはインデックスの存在判定(”0″ in arr)。値の存在はarr.includes(value)。- 対策: 目的に合ったAPIを使う(配列はincludes、Setはhas)。
- hasOwnPropertyの偽装/上書き: オブジェクトが独自の
hasOwnPropertyを持つと危険。- 対策:
Object.hasOwn(obj, key)かObject.prototype.hasOwnProperty.call(obj, key)を使用。
- 対策:
- プロトタイプ由来を意図せず拾う: 既定メソッドまでtrueになる。
- 対策: 継承を除外したいときは必ず
Object.hasOwn。
- 対策: 継承を除外したいときは必ず
練習問題(手を動かして覚える)
// 1) in と hasOwn の違い
const base = { inherited: 1 };
const obj = Object.create(base);
obj.own = 2;
console.log("inherited" in obj); // true
console.log(Object.hasOwn(obj, "inherited"));// false
console.log(Object.hasOwn(obj, "own")); // true
// 2) undefined と不存在の違い
const a = { x: undefined };
console.log("x" in a); // true
console.log(a.x !== undefined); // false
console.log("y" in a); // false
// 3) 配列での誤用回避
const arr = ["red", "blue"];
console.log(0 in arr); // true(インデックス0はある)
console.log(arr.includes("red")); // true(値"red"はある)
JavaScript直感的な指針
- 名前の存在(継承含む):
'key' in obj - 自分が持つキーだけ:
Object.hasOwn(obj, 'key') - 値が設定済みか:
obj.key !== undefined - 配列の値存在:
arr.includes(value)を使う
この3つの視点(キーの存在/自前かどうか/値の有無)を分けて考えると、混乱が消えます。
