Code Fix

中級

NaNを===やswitchで判定できない理由と直し方

NaNはIEEE 754の仕様上、自分自身とも等しくないため、===はもちろん==でも決してtrueになりません。数値変換の失敗をチェックする際にこの性質を知らないと、判定が常にすり抜けます。

なぜエラーが出ないのか

出力: true
(エラーなし)
JavaScriptは何も報告しません。文法として正しいためです
出力: true
実際の挙動 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  function isValidAge(input) {
 2    const age = Number(input);
 3    return !(age === NaN      );
                       ^
 4  }
 5  console.log(isValidAge("abc"));
出力: true期待: false (エラーにはなりません)

NaNはどんな値(自分自身も含む)と比較してもfalseになります。存在チェックにはNumber.isNaN()という専用の関数が必要です。

直し方: age === NaN を Number.isNaN(age) にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  function isNumeric(input) {
 2    const n = parseFloat(input);
 3    return !(n === NaN      );
                      ^
 4  }
 5  console.log(isNumeric("abc"));
出力: true期待: false (エラーにはなりません)

parseFloatが変換に失敗するとNaNを返しますが、=== NaNでの判定は常にfalseになるため、失敗を検出できません。

直し方: n === NaN を Number.isNaN(n) にします。

この問題を解いてみる →

パターン3

 1  function isDivisible(a, b) {
 2    const result = a % b;
 3    return !(result === NaN      );
                         ^
 4  }
 5  console.log(isDivisible(5, 0));
出力: true期待: false (エラーにはなりません)

0による剰余演算はNaNになります。=== NaNでは検出できず、割り切れると誤判定してしまいます。

直し方: result === NaN を Number.isNaN(result) にします。

この問題を解いてみる →

パターン4

 1  function isValidScore(input) {
 2    const score = Number(input) * 1;
 3    return !(score === NaN      );
                        ^
 4  }
 5  console.log(isValidScore(undefined));
出力: true期待: false (エラーにはなりません)

Number(undefined)はNaNになります。=== NaNでは検出できないため、常にtrueを返してしまいます。

直し方: score === NaN を Number.isNaN(score) にします。

この問題を解いてみる →

パターン5

 1  function isSafe(a, b) {
 2    const ratio = a / b;
 3    return !(ratio === NaN      );
                        ^
 4  }
 5  console.log(isSafe(0, 0));
出力: true期待: false (エラーにはなりません)

0を0で割るとNaNになります(他の数を0で割ったInfinityとは別物です)。=== NaNでは判定できません。

直し方: ratio === NaN を Number.isNaN(ratio) にします。

この問題を解いてみる →

よくある誤解

「NaNはNaNと等しいはず」という直感に反し、NaN === NaNは常にfalseです。存在確認にはNumber.isNaN()という専用の関数を使う必要があります。

実務での勘所

NaN !== NaNという性質はJavaScript独自の癖ではなく、IEEE 754という浮動小数点数の国際規格自体がそう定めています。この規格に準拠する言語はほとんどすべて同じ挙動になります。JavaScriptにはNumber.isNaN()のほかにObject.is(NaN, NaN)という比較方法もあり、こちらはtrueを返します。Object.isは===とは別の「SameValue」というアルゴリズムを使っており、NaN同士や+0と-0の違いなど、===が特別扱いする例外にちょうど対称的な扱いをする、という関係になっています。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)