in 演算子とは何か
in 演算子は「そのキー(プロパティ名)が、オブジェクト“自身またはプロトタイプ上”に存在するか」を真偽値で返す演算子です。ここが重要です:in は「値があるか」ではなく「キーが存在するか」を調べます。値が undefined や null でも、キーがあれば true になります。
const user = { id: 1, name: undefined };
"id" in user; // true(キーがある)
"name" in user; // true(キーはある。値は undefined)
"age" in user; // false(キー自体が無い)
JavaScript基本動作(自身とプロトタイプまで含む)
自身と継承(プロトタイプ)を辿る
in は「自身に無ければプロトタイプへ」探索を続けます。
const base = { kind: "person" };
const obj = Object.create(base); // base を継承
obj.name = "Alice";
"name" in obj; // true(自身)
"kind" in obj; // true(継承元)
"age" in obj; // false
JavaScriptここが重要です:継承まで含めた“存在判定”をしたい場面(API の既定値がプロトタイプにあるなど)では in が便利です。逆に“自分が持っているキーだけ”を判定したいなら後述の Object.hasOwn を使います。
“キーがある”と“値がある”の違い(深掘り)
undefined/null と in の関係
値が空でもキーがあれば in は true。キーごと消さない限り false にはなりません。
const obj = { a: undefined, b: null };
// キーの存在
"a" in obj; // true
"b" in obj; // true
// 値の有無(用途が違う)
obj.a === undefined; // true
obj.b === null; // true
JavaScriptdelete と in の組み合わせ
delete で“キーごと”取り除くと、in は false になります。
const o = { x: 1 };
delete o.x;
"x" in o; // false
JavaScriptここが重要です:判定意図で使い分けます。キーの有無は in/Object.hasOwn、値の状態は比較(=== undefined/=== null)で見るのが安全です。
Object.hasOwn との違い(自前のキーだけ判定)
“自前のキーだけ”を判定する
継承を含めたくないときは Object.hasOwn(ES2022)か、古い環境なら obj.hasOwnProperty を使います。
const base = { kind: "base" };
const obj = Object.create(base);
obj.name = "Alice";
"kind" in obj; // true(継承も含む)
Object.hasOwn(obj, "kind"); // false(自前には無い)
Object.hasOwn(obj, "name"); // true
JavaScriptここが重要です:データ検証や“自分が持っているフィールドだけ”を送信したい場面では Object.hasOwn が適切です。in は“存在すればOK”という幅広い判定に向きます。
配列・文字列での in(スパースや長さの理解)
配列のインデックス存在判定
配列は“数値っぽいキー”をプロパティとして持ちます。穴(疎配列)かどうかの判定に使えます。
const arr = [];
arr[2] = "X"; // [ <2 empty items>, "X" ]
0 in arr; // false(穴)
1 in arr; // false(穴)
2 in arr; // true(値があるスロット)
JavaScript“length” は常に存在する
配列には “length” キーが常にあります。
"length" in arr; // true
JavaScript文字列のインデックス(読み取り専用)
文字列もインデックスでアクセス可能ですが、要素は不変です。
const s = "ABC";
0 in s; // true
3 in s; // false
s[0]; // "A"
JavaScriptここが重要です:配列の“穴かどうか”を in で判定でき、forEach/map は穴をスキップする点と合わせて設計すると挙動差で迷いません。
動的キー・安全な判定(例外回避と組み合わせ)
ブラケット記法と in(変数キー)
キーが変数や式ならブラケットで判定します。
const key = "title";
const article = { title: "Hello" };
key in article; // true
JavaScript右辺が null/undefined だと例外
in の右辺は“オブジェクト”が必要です。null/undefined だと TypeError になります。ガードを入れましょう。
const maybe = null;
// "x" in maybe; // TypeError
const exists = maybe != null && ("x" in maybe); // 安全
JavaScriptオプショナルチェーンは in には直接使えない
?. はプロパティアクセス用です。in と併用するならガード式(!= null)を使います。
ここが重要です:in の右辺ガードは鉄則です。外部入力やネストで null/undefined の可能性があるときは必ず守ってください。
Map/Set・for…in との違い(混同しない)
Map/Set は in ではなく専用メソッド
in は“オブジェクトのプロパティ”判定です。Map/Set のキー存在は .has を使います。
const m = new Map([["a", 1]]);
"a" in m; // false(プロパティではない)
m.has("a"); // true(Mapのキー)
JavaScriptfor…in と in は別物
- in 演算子: “key” in obj(キーの存在を真偽値で返す)
- for…in: オブジェクトの列挙用ループ(継承キーも回り得る)
列挙は Object.keys/entries を使い、必要なら Object.hasOwn で“自前のキー”に限定するのが初心者に安全です。
実践レシピ(存在判定の定番パターン)
入力検証:必須フィールドのチェック
function validateUser(u) {
if (u == null) return { ok: false, reason: "missing object" };
if (!("id" in u)) return { ok: false, reason: "missing id" };
if (!Object.hasOwn(u, "name")) return { ok: false, reason: "missing own name" };
return { ok: true };
}
JavaScript既定値の適用(キーが無ければ補う)
function withDefaults(cfg) {
const out = { ...cfg };
if (!("timeout" in out)) out.timeout = 5000; // キーが無いときだけ追加
return out;
}
JavaScriptフィーチャー検出(環境依存の安全な分岐)
function supportsIntl() {
return typeof Intl !== "undefined" && ("Collator" in Intl);
}
JavaScriptまとめ
in 演算子は「キーの存在」を判定する道具で、“値の有無”ではありません。継承まで含めて調べるため広い意味での存在確認に向き、一方で“自前のキーだけ”が必要なら Object.hasOwn を使います。配列の穴判定、文字列インデックス、動的キーのブラケット併用、右辺ガード(null/undefined 対策)、Map/Set には .has を使うことを押さえれば、初心者でも安全で意図通りの存在判定が書けます。
