JavaScript | 配列・オブジェクト:オブジェクト基礎 – in 演算子

JavaScript JavaScript
スポンサーリンク

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
JavaScript

delete と 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のキー)
JavaScript

for…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 を使うことを押さえれば、初心者でも安全で意図通りの存在判定が書けます。

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