エンジニアの皆さん、お疲れ様。コードを書いていると、「この変数は本当にDateオブジェクトなのか?」と頭を抱える瞬間、一度は経験するよね。
APIから飛んできたJSONをパースした時、あるいはサードパーティのライブラリとデータをやり取りする時。JavaScriptの「型」という曖昧な境界線は、時としてバグの温床になる。今日は、現場で「ハマりどころ」になりがちなDateオブジェクトの判定について、深掘りしていこう。
—
1. なぜ `typeof` は役に立たないのか
まず、基本の確認だ。JSの `typeof` は、プリミティブ型を判別するには優秀だが、オブジェクトに対しては無力に等しい。
const date = new Date();
console.log(typeof date); // “object”
見ての通り、`typeof` で判定できるのは「オブジェクトであること」までだ。配列だろうが、Dateだろうが、自作のクラスだろうが、すべてが `object` に丸め込まれる。これでは、「日付型として処理したいのに、普通のオブジェクトが混入してクラッシュする」という悲劇を止められない。
—
2. `instanceof` の限界と脆さ
次に思い浮かぶのが `instanceof` だ。直感的だし、コードも短い。
if (val instanceof Date) {
// 日付の処理…
}
これで大抵はうまくいく。だが、実務レベルで考えるなら「落とし穴」を理解しておく必要がある。最も有名なのが、「iframeをまたいだ環境」だ。
ブラウザの裏側では、各ウィンドウやiframeごとに独立したグローバル実行コンテキストが存在する。もし別のフレームで生成されたDateオブジェクトをメインウィンドウに渡した場合、`instanceof` は `false` を返す。なぜなら、そのDateの「設計図(コンストラクタ)」が別物だと判断されるからだ。現代のSPA開発ではiframeを多用することは減ったが、マイクロフロントエンドのような構成では、この「見えない境界線」がバグを呼ぶことがある。
—
3. 最強の判定術:`Object.prototype.toString.call`
そこで、現場のシニアたちが最終的に行き着くのがこれだ。「内部的なクラス名(`[[Class]]`)」を直接覗き見する手法だ。
/
- 確実にDateオブジェクトかどうかを判定するユーティリティ関数
- @param {} val
- @returns {boolean}
/
function isDate(val) {
return Object.prototype.toString.call(val) === ‘[object Date]’;
}
// 動作確認
console.log(isDate(new Date())); // true
console.log(isDate({})); // false
console.log(isDate(“2023-01-01”)); // false
なぜこれが最強なのか?
JavaScriptのエンジンは、オブジェクトが生成された時に内部プロパティ `[[Class]]` にその正体を刻み込む。この `toString` メソッドを明示的に呼び出すことで、プロトタイプチェーンや実行コンテキストの壁を越えて、そのオブジェクトの「正体」を確定できるんだ。
—
4. 実務で「もう一歩先」を行くために
さて、ここまでが教科書的な話だ。しかし、実務では「Invalid Date」という厄介な存在を忘れてはいけない。
`new Date(‘hogehoge’)` を実行した時、JSは例外を投げるのではなく、`Invalid Date` という「見た目はDateだが、中身は死んでいる」オブジェクトを生成する。`isDate` を通せば `true` になるが、その後の `getTime()` を呼ぶと `NaN` が返ってくる。
現場で信頼性の高い判定を行うなら、こう書きたい。
/
- 完全に有効なDateオブジェクトかを判定する
/
function isValidDate(val) {
// 1. まずはDateオブジェクトかどうかを確認
if (Object.prototype.toString.call(val) !== ‘[object Date]’) {
return false;
}
// 2. getTime() が NaN ではないことを確認(これがInvalid Dateの判定)
return !isNaN(val.getTime());
}
const invalidDate = new Date(‘invalid-string’);
console.log(isDate(invalidDate)); // true (騙される!)
console.log(isValidDate(invalidDate)); // false (正解!)
—
最後に:コードは「防御」のためにある
JavaScriptは自由度の高い言語だ。しかし、自由度は「いつの間にかデータ型が壊れる」というリスクと隣り合わせだ。
今回紹介した `Object.prototype.toString.call` をベースにした判定は、派手ではないし、タイプ数も多い。だが、チーム開発において「確実性」を担保することは、後から自分のコードを読む未来の自分や、デバッグに追われる同僚に対する最大の誠意だ。
迷ったら「一番堅い方法」を選ぶ。それが、複雑なフロントエンドの世界を生き抜くための、職人の知恵だと思っておいてくれ。また何か疑問があったら、いつでも聞きに来るといい。

コメント