JavaScript | 基礎構文:数値・演算 – NaN

JavaScript JavaScript
スポンサーリンク

NaN を一言でいうと

NaN(ナン)は
「Number(数値)型なんだけど、“正しい数ではない” という特別な値」 です。

名前は Not a Number の略ですが、
「数値じゃない」と言いつつ、型としては number というややこしい存在です。

ここが重要です。
NaN は
「数値計算しようとしたけど、まともな数字にならなかった」という“エラーの結果”を表すための特別な数値
だととらえてください。


NaN はどういうときに出てくるのか

数値に変換できないものを数値計算しようとしたとき

一番よくあるのは、
「数字っぽくない文字列」で計算しようとしたとき です。

console.log("hello" * 2);     // NaN
console.log("abc" - 1);       // NaN
console.log(parseInt("xyz")); // NaN
JavaScript

"hello" * 2 のとき、JavaScript は
「”hello” を数値にして掛け算しよう」としますが、
どうやっても数値にならないので、結果として NaN になります。

0 で割ったとき「必ず」NaN になるわけではない

ここは勘違いしやすいところです。

console.log(10 / 0);  // Infinity(無限大)
console.log(-10 / 0); // -Infinity
console.log(0 / 0);   // NaN
JavaScript

「0 で割った=NaN」ではありません。
10 / 0 のように「0 を含まない数を 0 で割る」と Infinity(無限大)になり、
「0 / 0」のように結果が定義できないときに NaN になります。

Math 関数に変な値を渡したとき

console.log(Math.sqrt(-1));    // NaN(実数の範囲外)
console.log(Math.log(-1));     // NaN(対数が定義できない)
console.log(Math.max(1, 2, NaN)); // NaN(中に NaN が混じっている)
JavaScript

「数学的に定義できない」ような計算をすると NaN になる、とイメージしておくと良いです。

ここが重要です。
NaN は「エラーそのもの」ではなく
「計算した結果、意味のある数にならなかった」という“結果の値” です。
だから普通の値のように他の計算に混ざって流れていきます。


NaN のやっかいな性質①:何と計算しても NaN が広がる

一度 NaN が混ざると、計算結果も NaN になる

const x = NaN;

console.log(x + 1);     // NaN
console.log(x - 1);     // NaN
console.log(x * 10);    // NaN
console.log(x / 2);     // NaN
console.log(Math.sqrt(x)); // NaN
JavaScript

どんな計算をしても、NaN が混ざっていると結果も NaN になってしまいます。
これは、「一度壊れた数値は、以降の計算も信頼できない」 という考え方です。

ここが重要です。
NaN は「数値の世界に生じたウイルス」みたいなもので、
一度入り込むと、その後の計算をどんどん汚染していきます。
だから、“NaN が混ざった時点で早く気付くこと” がすごく大事
です。


NaN のやっかいな性質②:自分自身とすら「等しくない」

NaN === NaN が false になる理由

びっくりポイントです。

console.log(NaN === NaN); // false
console.log(NaN == NaN);  // false
JavaScript

NaN 同士を比較しても、「等しい」と判定されません。
つまり、
=== NaN== NaN で NaN をチェックすることはできない
ということです。

これは「NaN は“特定の値”ではなく、“意味のある数じゃない状態”を表している」
という哲学的な理由からそうなっています。

じゃあ、NaN かどうかはどう判定するのか

JavaScript では、
isNaN / Number.isNaN
の 2 つが代表的なチェック方法です。

次の章で違いを説明します。

ここが重要です。
NaN は「唯一、自分自身とすら一致しない値」。
value === NaN でチェックしたくなる気持ちをぐっとこらえて、
「NaN 判定には専用の関数を使う」と体に刻んでおくのが大事です。


NaN 判定:isNaN と Number.isNaN の違い

古くからある isNaN(ざっくり判定)

isNaN(value) は、
「その値を数値に変換しようとしてダメだったか?」
を判定する関数です。

console.log(isNaN(NaN));        // true
console.log(isNaN(123));        // false
console.log(isNaN("hello"));    // true  (数値に変換できない)
console.log(isNaN("123"));      // false (数値に変換できる → 123)
console.log(isNaN(undefined));  // true
console.log(isNaN(null));       // false(null → 0 に変換される)
JavaScript

"hello" に対して true になるのは、
一度 Number("hello") してみて、それが NaN になるからです。

つまり isNaN は、
「数値に変換してもダメなやつ全部」=「NaN っぽく扱うべきもの」
を true と判断します。

より厳密な Number.isNaN(本当に NaN かだけを見る)

Number.isNaN(value) は、
「その値が、型として number で、かつ中身が NaN かどうか」
だけを見ます。

console.log(Number.isNaN(NaN));        // true
console.log(Number.isNaN(123));        // false
console.log(Number.isNaN("hello"));    // false(string なので)
console.log(Number.isNaN("123"));      // false
console.log(Number.isNaN(undefined));  // false
console.log(Number.isNaN(Number("hello"))); // true(Number("hello") は NaN)
JavaScript

ここが重要です。
実務では、
「既に数値として扱っている値が、NaN になってないか確認したい」 → Number.isNaN を使う
というのが安全です。

isNaN は「何でも数値変換してみてから判定」するので、
「文字列入力をざっくり数値チェックしたい」ときなどに限定して使うとよいです。


NaN が混ざりがちなパターンと対処法

ユーザー入力をそのまま計算に使う

const input = "abc";          // 本当は数字を入れてほしかった
const num = Number(input);    // NaN

console.log(num * 2);         // NaN(以降の計算が全部 NaN)
JavaScript

ここで大事なのは、
「Number(input) した時点で NaN かどうかをチェックする」 ことです。

const input = "abc";
const num = Number(input);

if (Number.isNaN(num)) {
  console.log("数値として無効な入力です");
} else {
  console.log(num * 2);
}
JavaScript

数値と一緒に計算しているのに、途中で NaN になる

例えば、配列の中に混ざった「変な値」。

const nums = [10, 20, "abc", 30];
let sum = 0;

for (const n of nums) {
  sum += Number(n);
}

console.log(sum); // NaN(途中で NaN が混ざる)
JavaScript

この場合も、
Number に変換したタイミングでチェックします。

const nums = [10, 20, "abc", 30];
let sum = 0;

for (const n of nums) {
  const value = Number(n);
  if (Number.isNaN(value)) {
    console.log("数値にできない要素がありました:", n);
    continue; // スキップするなど
  }
  sum += value;
}

console.log(sum); // 60
JavaScript

ここが重要です。
NaN は「早期発見・早期隔離」が命。
「数値に変換する入口」で Number.isNaN を使ってチェックし、
そこを通過した値だけを計算に入れるようにすると、バグの連鎖を防げます。


NaN と typeof、Number 型との関係

NaN も typeof すると “number”

console.log(typeof NaN);        // "number"
console.log(typeof 123);        // "number"
console.log(typeof 1.23);       // "number"
JavaScript

NaN も「数値型」の一種です。
「数値としての意味はないけど、型としては number」
という不思議な立ち位置です。

これは

  • 0
  • 正の数
  • 負の数
  • Infinity(無限大)
  • NaN

のようなものを、全部ひっくるめて「number 型」として扱っているからです。

NaN と null / undefined との違いを整理する

console.log(typeof null);      // "object"(歴史的な仕様)
console.log(typeof undefined); // "undefined"
console.log(typeof NaN);       // "number"
JavaScript

null / undefined は
「値そのものが存在しない」系の概念ですが、

NaN は
「数値計算をしようとした結果、まともな数にならなかった」
という立ち位置です。

ここが重要です。
「存在しない」系(null/undefined)と、「計算できなかった」系(NaN)は意味が違う。
NaN は、“数値の世界のエラー状態” を表す値だと整理しておくと、頭がすっきりします。


初心者として NaN で本当に押さえてほしいこと

NaN は Not a Number の略だが、型としては number。
「数値計算の結果が“まともな数にならなかった”ことを表す特別な数値」。

"hello" * 20 / 0Math.sqrt(-1) のような「数学的に意味をなさない計算」で NaN になる。

NaN は何と計算しても NaN になり、
さらに NaN === NaN が false になるため、
比較演算子では検出できない。

NaN 判定には
Number.isNaN(value)(本当に NaN かだけを見る)
を基本として使う。

ここが重要です。
NaN を怖がる必要はありません。
「数値に変換するタイミングで NaN チェックをする」
「計算結果がおかしそうなときは console.log(value, Number.isNaN(value)) してみる」
この 2 つを習慣にするだけで、NaN はむしろ“バグを教えてくれるありがたい存在”になります。

最後に、NaN の挙動を自分の目で確かめるための小さな練習を置いておきます。

const values = ["123", "abc", 0 / 0, 10 / 0, Math.sqrt(-1)];

for (const v of values) {
  console.log(
    "value:", v,
    "| typeof:", typeof v,
    "| == NaN:", v == NaN,
    "| === NaN:", v === NaN,
    "| isNaN:", isNaN(v),
    "| Number.isNaN:", Number.isNaN(v)
  );
}
JavaScript

これを実行して結果を眺めると、
「NaN がどう扱われるか」「どの判定が何に反応するか」がかなりクリアに理解できるはずです。

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