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

エンジニアの皆さん、お疲れ様。コードを書いていると、「この変数は本当に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` をベースにした判定は、派手ではないし、タイプ数も多い。だが、チーム開発において「確実性」を担保することは、後から自分のコードを読む未来の自分や、デバッグに追われる同僚に対する最大の誠意だ。

迷ったら「一番堅い方法」を選ぶ。それが、複雑なフロントエンドの世界を生き抜くための、職人の知恵だと思っておいてくれ。また何か疑問があったら、いつでも聞きに来るといい。

コメント

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