Skip to main content

Command Palette

Search for a command to run...

NaN (Not a Number) in JavaScript — in plain words

Published
2 min read
NaN (Not a Number) in JavaScript — in plain words
A

Hi, I’m Aashish, a developer who documents his confusion so others can skip it. Most of what I write starts as a messy Notion page, but ends up as something other devs can actually use. Currently obsessed with integrating Typescript/React/Next with Laravel and making code readable enough that future me won’t file a bug report. Occasionally seen holding a guitar and pretending it’s therapy.

NaN shows up when JavaScript tries to make a number, but it can’t. You’ll see it a lot while parsing strings or doing invalid math. Fun fact: typeof NaN is "number".

A quick look with parseInt

Here foo looks like a number, but its type is string. Using parseInt turns it into a real number.

let foo = "1";
console.log(parseInt(foo));        // 1
console.log(typeof parseInt(foo)); // "number"

Now, what if foo is not a number string but any other string? parseInt can’t make foo number, so it returns NaN.

let foo = "Momo";
console.log(parseInt(foo));        // NaN
console.log(typeof parseInt(foo)); // "number"

NaN is kind of unique

In JS, NaN is never equal to anything, not even itself. So we cannot use === to check NaN.

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

To check for NaN, use Number.isNaN(value). isNaN(value) also works, but it coerces values first.

let foo = 'Momo';

isNaN(foo);         // true   (coerces foo (which is a string) to -> NaN)
Number.isNaN(foo);  // false  (foo is not the NaN value but is a string)

Note: Object.is(NaN, NaN) is also true. It’s another safe way to compare with NaN.

Object.is(NaN, NaN); // true

More ways NaN appears

It’s not only about parsing. Any invalid math can cause NaN.

0 / 0;                // NaN
Math.sqrt(-1);        // NaN
Infinity - Infinity;  // NaN
"abc" * 2;            // NaN
"10" - "a";           // NaN
Number(undefined);    // NaN

parseInt vs Number vs parseFloat

parseInt stops at the first non‑digit. Number needs the whole string to be valid.

parseInt("3.14px", 10); // 3
parseFloat("3.14px");   // 3.14
Number("3.14px");       // NaN

Practical checks you will use

Check for a real, usable number. This avoids NaN and Infinity.

function isRealNumber(foo) {
  return typeof foo === "number" && Number.isFinite(foo);
}

Safely turn user input into a number. Return null if it’s not valid.

function toNumberOrNull(input) {
  if (String(input).trim() === "") return null;
  const n = Number(input);
  return Number.isNaN(n) ? null : n;
}

JSON note

JSON does not support NaN. It becomes null when you stringify.

JSON.stringify({ a: NaN }); // '{"a":null}'

Tiny cheat sheet

  • typeof NaN === "number"

  • NaN === NaN is false

  • Use Number.isNaN(x) for checks

  • isNaN(x) coerces, be careful

  • Comparisons with NaN are always false

Final note

Anything === NaN will always return false. Also, typeof NaN is "number". Keep these in mind, and NaN stops being scary.