JavaScript における値の型判定は、一見単純に見えるが、実際には typeof 演算子だけでは不十分なケースが多く存在します。たとえば、null は "object" を返し、配列や日付オブジェクトも同様に "object" と判定されます。Lodash はこの課題に対処するため、baseGetTag 関数を用いて、内部的により信頼性の高い型識別を行っています。
この関数の核となるのは、Object.prototype.toString の呼び出しです。しかし、ES5 から ES2015(ES6)へと仕様が進化する中で、[[Class]] 内部プロパティの代わりに Symbol.toStringTag が導入され、型文字列の生成ロジックが再定義されました。Lodash の実装は、両方の環境への互換性を保ちながら、正しい型タグ(例:"[object Array]")を返すよう細かく調整されています。
基本的な動作
baseGetTag は、引数の値に基づき、標準化された型ラベル文字列を返します:
import baseGetTag from 'lodash/_baseGetTag';
baseGetTag('hello'); // "[object String]"
baseGetTag([1, 2, 3]); // "[object Array]"
baseGetTag(new Date()); // "[object Date]"
baseGetTag(null); // "[object Null]"
baseGetTag(undefined); // "[object Undefined]"
Null と Undefined の特別処理
ECMAScript 5 より前では、Object.prototype.toString.call(null) や同様の呼び出しは、ブラウザ依存の挙動を示すことがありました。そのため、Lodash は明示的に null および undefined を検出し、それぞれ固定の文字列を返します:
if (value == null) {
return value === undefined ? '[object Undefined]' : '[object Null]';
}
Symbol.toStringTag の安全な利用
ES2015 以降では、任意のオブジェクトが Symbol.toStringTag プロパティを定義することで、toString() の出力をカスタマイズできます。ただし、このプロパティが存在すると、本来の組み込み型識別が上書きされる可能性があります。Lodash はこれを回避するために、一時的にそのプロパティを無効化してから元の型情報を取得し、その後状態を復元します:
const toString = Object.prototype.toString;
const symToStringTag = typeof Symbol !== 'undefined' ? Symbol.toStringTag : undefined;
function baseGetTag(value) {
if (value == null) {
return value === undefined ? '[object Undefined]' : '[object Null]';
}
// Symbol.toStringTag が未サポート、または対象オブジェクトに存在しない場合は直接呼び出し
if (!symToStringTag || !(symToStringTag in Object(value))) {
return toString.call(value);
}
const obj = Object(value);
const hasOwnTag = Object.prototype.hasOwnProperty.call(obj, symToStringTag);
const originalTag = obj[symToStringTag];
let tagWasModified = false;
try {
obj[symToStringTag] = undefined;
tagWasModified = true;
} catch (ignored) {}
const result = toString.call(obj);
// 復元処理:自身のプロパティだった場合は元の値を戻す、そうでなければ削除
if (tagWasModified) {
if (hasOwnTag) {
obj[symToStringTag] = originalTag;
} else {
delete obj[symToStringTag];
}
}
return result;
}
設計上の意図
この実装は、以下の点で堅牢性を確保しています:
- 環境非依存性:Symbol 未対応環境でも動作するフォールバックパスを備える
- 副作用の抑制:
Symbol.toStringTagの変更は一時的であり、呼び出し後のオブジェクト状態は元に戻される - 継承の区別:プロパティが自身のものか、プロトタイプチェーン経由かを正確に判断し、復元動作を分岐させる
このアプローチにより、Lodash は異なる JavaScript 実行環境においても、一貫した型識別結果を提供することが可能になります。