【実務・中級編】 MapおよびSetオブジェクトの型判定 – JavaScript実践ガイド

JavaScriptの「型判定」という深淵:MapとSetを正しく見極めるための現場の知恵

フロントエンドの現場でコードを書いていて、「これ、本当にMapなの?」と不安になったことはないだろうか?

`typeof` が万能だと思っていた新人時代、`typeof new Map()` を叩いて `object` という無機質な結果が返ってきた時のあの脱力感。あれこそが、JavaScriptという言語が抱える「オブジェクトの海」に足を踏み入れた瞬間だ。

今日は、中級エンジニアの君たちに向けて、MapやSetといったES6以降の強力なコレクションを、いかに「泥臭く、かつエレガントに」判定するか、その核心を解説しよう。

—

なぜ `typeof` では不十分なのか

まず結論から言うと、`typeof` はプリミティブ(`string`, `number`, `boolean`, `undefined`, `symbol`, `bigint`)を判定するための武器であって、オブジェクトの正体を暴くためのものではない。

`typeof` は、仕様上「それがオブジェクトか否か」の二択しか教えてくれない。`Map` も `Set` も、さらには `null` すらも `object` と判定される。これでは現場のバリデーションやデータ変換ロジックで使い物にならない。

`instanceof` という名の「血縁関係」チェック

じゃあどうするか? そこで登場するのが `instanceof` 演算子だ。これは、オブジェクトのプロトタイプチェーンを遡り、「そのコンストラクタのインスタンスであるか」を判定する。

const myMap = new Map();

// 直感的で分かりやすい判定
console.log(myMap instanceof Map); // true
console.log(myMap instanceof Object); // true (プロトタイプチェーンを遡るため)

非常にシンプルだが、ここで一つ注意点がある。「異なる実行コンテキスト(iframeなど)」を跨ぐ場合、`instanceof` は平気で裏切る。 別のウィンドウ(iframe)で生成された `Map` インスタンスは、親ウィンドウの `Map` とは別物(異なるプロトタイプ)として扱われるからだ。

現場で本当に信頼できる「Object.prototype.toString」という職人芸

大規模なフレームワークやライブラリのソースコードを覗くと、必ずと言っていいほど出会うのが `Object.prototype.toString.call()` による判定だ。これは、JavaScriptエンジンが内部的に保持している `[[Class]]` という内部スロットを直接覗き見るような、いわば「裏口」に近い手法だ。

この手法の素晴らしいところは、コンテキスト(iframe)の違いに依存せず、型を正確に射抜ける点にある。

/

  • 現場で使い回せる、堅牢なコレクション判定ユーティリティ

/
const getTag = (value) => Object.prototype.toString.call(value);

const isMap = (value) => getTag(value) === ‘[object Map]’;
const isSet = (value) => getTag(value) === ‘[object Set]’;

// 検証用コード
const mySet = new Set([1, 2, 3]);
console.log(isSet(mySet)); // true
console.log(isSet({})); // false

なぜこれが「最強」と言えるのか

`Object.prototype.toString.call(value)` は、値が何であれその型を `[object Type]` という文字列で強制的に変換してくれる。

  • `Map` なら `[object Map]`
  • `Set` なら `[object Set]`
  • `Date` なら `[object Date]`

これを知っているだけで、デバッグのスピードが劇的に変わる。「APIから返ってきた謎のデータが、実は期待していたMapじゃなくてただのオブジェクトだった」というバグに遭遇した時、このユーティリティがあれば一瞬で真実を突き止められる。

—

実務で意識すべき「境界条件」

最後に、一つだけアドバイスしておこう。現場でコードを書くとき、`Map` かどうかを判定する目的はなんだ? ほとんどの場合、「後続の処理で `.get()` や `.has()` を呼び出したいから」だろう。

もし、判定した後に安全にメソッドを呼び出したいなら、こう書くのがプロの嗜みだ。

function safeGet(collection, key) {
// Mapかどうかを厳密に判定し、安全に値を取得する
if (Object.prototype.toString.call(collection) === ‘[object Map]’) {
return collection.get(key);
}

// マップでない場合は、念のためundefinedを返すか、エラーを投げる設計にする
console.warn(‘期待されたMapではありません’);
return undefined;
}

まとめ:型判定は「防衛」である

JavaScriptは自由奔放な言語だ。だからこそ、我々エンジニアはデータが期待通りであることを「防衛」しなければならない。

1. `typeof` はプリミティブ用。オブジェクトの詳細判定には使わない。
2. `instanceof` は手軽だが、iframeを跨ぐ境界には注意。
3. 最強の切り札は `Object.prototype.toString.call()` 。これこそが、どんな環境でも揺るがない「型判定の真実」だ。

今日の知識を武器に、君が書くコードがより堅牢なものになることを期待している。仕様の裏側を覗く癖を忘れず、泥臭く、しかし誰よりもスマートなコードを書き続けてくれ。応援しているよ。

コメント

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