SKU // 101

JavaScript NaN

NaN stands for "Not a Number." It is the value JavaScript gives you when a calculation has no sensible numeric answer. You met it briefly in JS Numbers; this lesson covers where it comes from, why it spreads through your math, and the one correct way to check for it.

// Where NaN Comes From

You get NaN whenever JavaScript tries to do math and cannot produce a real number:

console.log(100 / "Apple");       // "Apple" cannot become a number
console.log(100 / "10");          // "10" CAN become a number: no NaN
console.log(0 / 0);
console.log(Math.sqrt(-1));
console.log(parseInt("abc"));
console.log(Number("12px"));
console.log(undefined + 1);
console.log(Infinity - Infinity);
NaN 10 NaN NaN NaN NaN NaN NaN

Notice the second line. JavaScript converts a numeric string like "10" to a number before dividing. Only text that cannot be read as a number, like "Apple", produces NaN.

// NaN Is a Number

It sounds like a contradiction, but NaN belongs to the number type. It is a special number value that means "this math went wrong":

console.log(typeof NaN);
number

// NaN Spreads

Any math that touches NaN gives NaN. One bad value can quietly ruin every result that depends on it. A classic source is averaging an empty list, which divides 0 by 0:

const scores = [];
let sum = 0;
for (const s of scores) sum += s;

console.log(sum / scores.length);                 // 0 / 0
console.log(NaN + 5, Math.round(NaN), Math.max(1, NaN));
console.log("Average: " + sum / scores.length);
NaN NaN NaN NaN Average: NaN
Debugging Habit
When a result shows NaN, work backward through the calculation and log each input. The bug is almost never in the last step; it is the first value that was already NaN, or text that never became a number.

// NaN Is Not Equal to Itself

NaN is the only value in JavaScript that is not equal to itself. Every comparison with it is false:

const x = NaN;
console.log(x == x, x === x);
console.log(NaN > 0, NaN < 0, NaN >= NaN);
console.log(x !== x);    // true ONLY when x is NaN
false false false false false true
Watch out: === NaN never works
if (result === NaN) is always false, even when result is NaN. You need a function that checks for it.

// Checking for NaN: isNaN() vs Number.isNaN()

There are two functions, and they give different answers. The older global isNaN() converts its argument to a number first, then checks. Number.isNaN() (added in 2015) does no converting: it is only true for the actual NaN value.

console.log(isNaN("Apple"), Number.isNaN("Apple"));
console.log(isNaN(undefined), Number.isNaN(undefined));
console.log(isNaN(""), isNaN("12"));          // both convert to real numbers
console.log(Number.isNaN(NaN), Number.isNaN(0 / 0));
true false true false false false true true

"Apple" is a string, not NaN. The global isNaN says true only because Number("Apple") would be NaN. That makes it a "would this fail as a number?" test, which is sometimes what you want, but it is easy to misread.

W3Schools error
W3Schools says "To test for NaN, use isNaN()." The global isNaN() converts first, so isNaN("Apple") is true even though "Apple" is not NaN. To test whether a value is NaN, use Number.isNaN().
Check x = NaN x = "Apple" x = 5
x !== xtruefalsefalse
isNaN(x)truetruefalse
Number.isNaN(x)truefalsefalse
Number.isFinite(x)falsefalsetrue

The last row is often the check you really want: Number.isFinite(x) is true only for a real, usable number (not NaN, not Infinity, and not a string).

// Where NaN Hides

Because NaN is not equal to itself, some tools cannot find it and others can:

const list = [1, NaN, 3];
console.log(list.indexOf(NaN), list.includes(NaN));
console.log(new Set([NaN, NaN]).size);
console.log(Object.is(NaN, NaN));
console.log(JSON.stringify({ total: NaN }));
-1 true 1 true {"total":null}

// Replacing NaN With a Fallback

NaN is one of the 8 falsy values, so || replaces it. But ?? does not, because it only replaces null and undefined:

const price = Number("free");

console.log(price || 0);                        // NaN is falsy: replaced
console.log(price ?? 0);                        // ?? ignores NaN
console.log(Number.isNaN(price) ? 0 : price);   // the precise version
0 NaN 0

// Real Example: Checking User Input

Text typed into a web page arrives as a string. Convert it, then check before using it:

const inputs = ["3", "three", "", "  "];

for (const text of inputs) {
  const qty = Number(text);
  console.log(JSON.stringify(text), qty, Number.isNaN(qty));
}
"3" 3 false "three" NaN true "" 0 false " " 0 false
Trap: an empty box is 0, not NaN
Number("") and Number(" ") are 0. If a user leaves a box blank, a NaN check will not catch it. Check for blank text first: if (text.trim() === "").

// Quick Check

What does this log?

console.log([NaN].indexOf(NaN), [NaN].includes(NaN));
Show answer
-1 true. indexOf compares with ===, and NaN === NaN is false, so it never finds it. includes handles NaN correctly.

Which of these is true?

  1. NaN === NaN
  2. isNaN("hello")
  3. Number.isNaN("hello")
  4. typeof NaN === "NaN"
Show answer
B. The global isNaN converts "hello" to a number first, which gives NaN. C is false because "hello" is a string, not NaN. D is false: typeof NaN is "number".

const total = Number(input) ?? 0; still gives NaN when input is "abc". Why, and how do you fix it?

Show answer
?? only replaces null and undefined, and NaN is neither. Use Number.isNaN(n) ? 0 : n, or || 0 if replacing a real 0 with 0 is fine too.

// Try It

  1. Click Open Playground. Produce NaN in five different ways and log each one
  2. Compare isNaN and Number.isNaN on "42", "forty-two", and NaN
  3. Write average(list) that returns 0 for an empty list instead of NaN
  4. Write readQuantity(text) that returns a number, or null for blank or non-numeric text
// Video Walkthroughs
Last updated: Oct 10, 2026, 1:48 AM ET