JavaScriptの開発において、数値計算の結果が期待通りにならない場合に遭遇する特別な値が「NaN」です。
NaNは「Not-a-Number」の略称であり、無効な算術演算の結果として生成される値ですが、その性質は非常に特殊です。
プログラムの中でNaNを正しく検出し、適切に処理することは、予期せぬバグを防ぐために極めて重要なスキルといえます。
特に、歴史的に使用されてきたグローバル関数のisNaNと、ES6で導入されたNumber.isNaNでは、判定の仕組みが大きく異なります。
本記事では、2026年現在のモダンなJavaScript開発において、これら2つのメソッドをどのように使い分けるべきか、具体的なコード例を交えて詳しく解説します。
NaNとはどのような値か
JavaScriptにおけるNaNは、データ型としては「数値(Number)」に分類されます。
実際にtypeof NaNを実行すると、結果は"number"と返されるため、初心者の方は混乱しやすいポイントかもしれません。
NaNは、例えば「文字列を数値に変換しようとして失敗したとき」や「0を0で割ったとき」などに発生します。
// NaNが発生する典型的な例
const result1 = "JavaScript" / 10; // 数値以外での除算
const result2 = parseInt("Hello"); // 数値に変換できない文字列のパース
const result3 = Math.sqrt(-1); // 負の数の平方根
console.log(result1);
console.log(result2);
console.log(result3);
NaN
NaN
NaN
このように、計算が数学的に定義できない場合や、数値として表現できない場合にJavaScriptエンジンはNaNを返します。
NaN判定における最大の罠:比較演算子
JavaScriptの基本的な知識として、値の比較には==(等価演算子)や===(厳密等価演算子)を使用します。
しかし、NaN判定においてはこれらの比較演算子は一切役に立ちません。
なぜなら、JavaScriptの仕様において、NaNは自分自身を含むあらゆる値と等しくないと定義されているからです。
// 自分自身と比較してもfalseになる
console.log(NaN === NaN);
console.log(NaN == NaN);
false
false
この特異な性質があるため、if (value === NaN)といったコードを書いても、常にfalseとなり、正しい判定を行うことができません。
そこで、JavaScriptにはNaNを判定するための専用の関数が用意されています。
グローバル関数 isNaN() の仕組みと注意点
古くからJavaScriptに存在するisNaN()は、引数として渡された値がNaNであるかどうかを判定するグローバル関数です。
一見便利に思えますが、この関数には「引数を数値に暗黙的に変換してから判定する」という強力な副作用があります。
そのため、実際にNaNではない値に対してもtrueを返してしまうケースが多く存在します。
// 本来はNaNではないが、isNaNがtrueを返す例
console.log(isNaN("Hello")); // 文字列を数値に変換しようとしてNaNになるためtrue
console.log(isNaN(undefined)); // undefinedは数値変換でNaNになるためtrue
console.log(isNaN({})); // オブジェクトも数値変換不能でNaNになるためtrue
true
true
true
このように、isNaN()は「その値がNaNであるか」ではなく、「その値を数値に変換したときにNaNになるか」をチェックしています。
この挙動は、厳密な型チェックが求められる現代のアプリケーション開発では、バグの原因になりやすい危険な仕様といえます。
ES6で登場した Number.isNaN() の優位性
ECMAScript 2015(ES6)以降、より厳密な判定が可能なNumber.isNaN()が導入されました。
このメソッドは、グローバル関数のisNaN()とは異なり、「引数が数値型であり、かつその値がNaNである場合」のみtrueを返します。
引数の型変換を一切行わないため、予期せぬ判定結果を招く心配がありません。
// Number.isNaNによる厳密な判定
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("Hello")); // false (数値型ではないため)
console.log(Number.isNaN(undefined)); // false (数値型ではないため)
console.log(Number.isNaN(123)); // false (数値だがNaNではない)
true
false
false
false
2026年現在のモダンなJavaScript環境では、特別な理由がない限りはNumber.isNaN()を使用することが標準的なプラクティスとなっています。
isNaN と Number.isNaN の比較表
両者の挙動の違いを整理するために、さまざまな入力値に対する結果を以下の表にまとめました。
| 入力値 | isNaN() | Number.isNaN() | 備考 |
|---|---|---|---|
NaN | true | true | 両者とも正しく判定 |
"abc" | true | false | isNaNは型変換を行う |
undefined | true | false | isNaNは型変換を行う |
null | false | false | nullは0に変換されるため |
true / false | false | false | 数値変換可能(1 / 0) |
この表からわかる通り、isNaN()は非数値の入力に対して非常に「寛容すぎる」判定を下してしまいます。
もう一つの判定方法:Object.is()
NaNを判定する手段は、これだけではありません。
JavaScriptの比較アルゴリズムをより厳密にしたObject.is()メソッドを使用する方法もあります。
Object.is(NaN, NaN)を実行すると、trueが返されます。
// Object.isによる判定
const value = NaN;
if (Object.is(value, NaN)) {
console.log("この値はNaNです");
}
この値はNaNです
Object.is()は、===(厳密等価)とほぼ同じですが、「NaN同士を等しいとみなす」点と「+0と-0を区別する」点において異なります。
単一の変数がNaNかどうかをチェックするだけであればNumber.isNaN()が最も直感的ですが、等価性のコンテキストでNaNを扱いたい場合にはObject.is()も有力な選択肢となります。
実践的なユースケースと実装パターン
実際のアプリケーション開発において、どのようにNaN判定を組み込むべきか、具体的なシーンを考えてみましょう。
1. ユーザー入力のバリデーション
HTMLのinput要素から取得した値は常に文字列型です。
これを数値に変換して計算に利用する際、変換後の値が妥当かどうかをチェックする必要があります。
function processAge(input) {
const age = Number(input);
// 数値変換に失敗してNaNになった場合を考慮
if (Number.isNaN(age)) {
console.error("年齢には有効な数値を入力してください");
return;
}
console.log(`あなたの年齢は ${age} 歳です`);
}
processAge("25"); // 正常
processAge("不明"); // エラーハンドリング
この例では、Number.isNaN()を使用することで、入力が数値変換可能な文字列だったかどうかを正確に判断しています。
2. 配列からのNaN抽出
データ処理の過程で混入したNaNをフィルタリングしたい場合も、Number.isNaN()が活躍します。
const mixedData = [10, "20", NaN, 30, "Hello", NaN];
// 配列内のNaNだけを特定する
const nanIndices = mixedData
.map((val, index) => Number.isNaN(val) ? index : -1)
.filter(index => index !== -1);
console.log("NaNが見つかったインデックス:", nanIndices);
NaNが見つかったインデックス: [2, 5]
2026年におけるベストプラクティス
現代のJavaScript、特にTypeScriptを併用する開発環境では、型安全性が重視されます。
グローバルなisNaN()は、引数にany型を許容するような緩い設計になっていることが多いため、基本的には推奨されません。
コードの意図を明確にし、型の強制的な変換によるバグを避けるために、以下の指針を守ることをお勧めします。
- 値がNaNであるかを調べたいときは、必ず
Number.isNaN()を使用する。 - 古いブラウザ(IEなど)への対応が不要な環境では、グローバルな
isNaN()を使う理由は一つもありません。 - 関数の戻り値としてNaNを返す可能性がある場合は、ドキュメントや型定義でその旨を明示する。
また、計算の途中でNaNが発生することを防ぐ「防衛的プログラミング」も重要です。
例えば、演算を行う前に値がundefinedやnull、または空文字でないかを確認することで、NaNの発生自体を未然に防ぐことができます。
まとめ
JavaScriptにおいて、NaNは自分自身とも等しくないという極めてユニークな性質を持つ値です。
そのため、===演算子による比較は機能せず、専用の判定メソッドを使用しなければなりません。
従来のisNaN()は引数の自動型変換によって意図しない結果を返すリスクがあるため、現代の開発ではNumber.isNaN()を利用するのが最も安全で確実な方法です。
「型を意識した厳密な判定」を行うことは、堅牢なアプリケーションを構築するための第一歩となります。
今回解説した違いを正しく理解し、適切なNaN判定を実装することで、数値計算にまつわるトラブルを最小限に抑えていきましょう。
