【JS応用|豆知識】なぜ「typeof」では不十分なのか?Object.prototype.toString.callで正確な型判定を行う方法

導入:なぜ型判定にObject.prototype.toString.callが必要なのか

フロントエンド開発において、変数の型を確認することはバグを未然に防ぐための第一歩です。JavaScriptには「typeof」演算子がありますが、これには「nullがobjectと判定される」「配列(Array)や正規表現(RegExp)がすべてobjectと判定される」という大きな弱点があります。複雑なデータを扱うモダンなアプリケーションでは、こうした曖昧さは予期せぬエラーの温床となります。そこで登場するのが、あらゆる型を正確に識別できる「Object.prototype.toString.call」というテクニックです。

基礎知識:JavaScriptの内部的な仕組み

JavaScriptのすべてのオブジェクトは、内部プロパティとして「[[Class]]」という情報を保持しています。通常、これに直接アクセスすることはできませんが、「Object.prototype.toString」メソッドを呼び出すことで、この内部情報を「[object 型名]」という文字列形式で取得できます。

通常のオブジェクトで「toString()」を呼ぶと、そのオブジェクトが独自に定義したtoStringメソッドが優先されてしまうことがあります。そこで、「call」メソッドを使って、Objectプロトタイプが持つ純粋なtoString関数を、判定したい対象に対して強制的に実行させるという仕組みです。

実装:正確な型判定の手順

実装は非常にシンプルです。判定したい値を引数として渡し、返ってきた文字列から「[object 」と「]」を取り除くことで、純粋な型名(”Array”, “Date”, “Null”など)を取得します。

サンプルプログラム

以下のコードをコピーしてコンソールで実行してみてください。typeofでは区別がつかない型も正確に判定できます。

/
  • 正確なデータ型を取得する関数
  • @param {any} value - 判定したい値
  • @returns {string} - 小文字の型名
/ function getType(value) { // Object.prototype.toStringを呼び出し、結果を[object Xxxx]形式で取得 const result = Object.prototype.toString.call(value); // 文字列の8文字目から最後の一文字前までを切り取り、小文字に変換 // 例: "[object Array]" -> "Array" -> "array" return result.slice(8, -1).toLowerCase(); } // 実行テスト console.log(getType([])); // "array" console.log(getType(null)); // "null" console.log(getType(/abc/)); // "regexp" console.log(getType(new Date())); // "date" console.log(getType({})); // "object" console.log(getType(123)); // "number"

応用・注意点:現場で役立つアドバイス

この手法は非常に強力ですが、いくつか注意点があります。

1. 独自クラスの判定には不向き
自分で定義したクラス(class User {}など)を判定しても、結果は常に「object」となってしまいます。独自クラスを判定したい場合は「instanceof」演算子を併用しましょう。

2. パフォーマンスへの配慮
非常に頻繁に(数万回単位で)呼び出されるループ処理の中で使うと、わずかながらオーバーヘッドになります。一般的なUI操作やバリデーションであれば問題ありませんが、極限までパフォーマンスを求める箇所では考慮が必要です。

3. ユーティリティ化して管理する
プロジェクト全体でこの関数を一つ定義しておくと、型判定の揺れがなくなり、メンテナンス性が向上します。lodashなどのライブラリを使えない環境では、必須級のテクニックと言えるでしょう。

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