現場でコードを書いていると、「数値だと思っていたものが、実は数値じゃなかった」というバグに何度泣かされたことか。
今回は、JavaScript界の「厄介者」でありながら、避けては通れない`NaN`(Not-a-Number)の話をしよう。中級者なら一度はハマるこの落とし穴を、今日で完全に攻略してほしい。
—
1. なぜ「数値」なのに「数値ではない」のか?
まず、大前提として知っておいてほしいのは、`NaN`は「数値ではない」という意味でありながら、型としては`number`であるという矛盾した性質だ。
console.log(typeof NaN); // “number” と出力される。これが全ての悲劇の始まりだ。
`NaN`は、数学的に定義できない計算(`0 / 0`や`Math.sqrt(-1)`など)を行った結果として返される。IEEE 754という浮動小数点数の規格上、これは「数値型の一種」として扱われるからだ。ブラウザのエンジンがこの値を計算結果として返すのは、プログラム全体をクラッシュさせないための「安全装置」のようなものだが、開発者にとってはデバッグの魔物でしかない。
—
2. 最大の罠:`NaN`は自分自身と一致しない
ここがJavaScriptの面白い(そして極悪な)ところだ。`NaN`は、世界で唯一「自分自身と等しくない」値である。
console.log(NaN === NaN); // false
もし君が、「値が`NaN`かどうか」を判定するために `if (x === NaN)` と書いているなら、それは今すぐやめよう。それは一生`false`を返し続ける。かつては`isNaN()`関数が使われていたが、これにも重大な欠陥がある。
古い`isNaN()`の危うさ
`isNaN()`は、渡された値を一度数値に強制変換(暗黙の型変換)してからチェックを行う。これが現場で予期せぬバグを量産する。
console.log(isNaN(“Hello”)); // true (文字列は数値に変換するとNaNになるから)
console.log(isNaN(“123”)); // false (数値に変換できるから)
console.log(isNaN(undefined)); // true (これ、バグの温床になりがち)
「数値がどうかを判定したいのに、文字列の”Hello”まで`true`判定されてしまう」――これでは実務では使えない。
—
3. 実務で採用すべき「正しい判定方法」
モダンなJavaScript環境(ES6以降)で生きる我々が使うべきは、`Number.isNaN()`、あるいはより厳密な`Object.is()`だ。
推奨1:`Number.isNaN()`
これは「型変換を行わない」。純粋に「その値が`NaN`であるか」だけを判定する。これこそが、僕らが求めていた挙動だ。
const value = “Hello”;
// 厳密に判定してくれる
console.log(Number.isNaN(value)); // false (正解!文字列はNaNではない)
console.log(Number.isNaN(NaN)); // true
推奨2:`Object.is()`
`Object.is()`は、`===`演算子とほぼ同じだが、`NaN`の扱いだけが特別に設計されている。「厳密な同値判定」を行いたいなら、これを使うのが最も美しい。
const result = 0 / 0; // NaNになる
// NaNであるかどうかを判定する究極の書き方
if (Object.is(result, NaN)) {
console.log(“計算結果はNaNです。入力値を確認してください。”);
}
—
4. 現場で役立つ実践的なパターン
APIから返ってきたレスポンスをバリデーションする際、僕ならこう書く。
/
- 数値として妥当かどうかを判定する関数
- @param {any} value
- @returns {boolean}
/
const isValidNumber = (value) => {
// 1. 型が数値であること
// 2. NaNではないこと
// 3. 有限数であること (Infinityも弾く)
return typeof value === ‘number’ && Number.isFinite(value);
};
// 使用例
console.log(isValidNumber(100)); // true
console.log(isValidNumber(NaN)); // false
console.log(isValidNumber(Infinity)); // false
console.log(isValidNumber(“100”)); // false (型チェックが効いている)
—
シニアからのアドバイス
`NaN`を扱うときに一番怖いのは、「暗黙の型変換によって、いつの間にか`NaN`が紛れ込んでいる」ことだ。
フロントエンドのフォーム入力や、APIのJSONデータは、常に「予期せぬ型」が入ってくる可能性がある。だからこそ、安易な比較演算子(`==`や`===`)に頼らず、`Number.isNaN()`や`Number.isFinite()`といった、言語仕様が提供する「意図が明確なメソッド」を積極的に使ってほしい。
「動けばいいコード」を書くのはジュニアまで。僕らプロは、「誰が見ても予期せぬ挙動をしない、堅牢なコード」を書く。`NaN`を制する者は、JavaScriptのデータフローを制する。今日のこの知識を、ぜひ明日のコードレビューで活かしてくれ。

コメント