Skip to main content

What is nan in JavaScript?

NaN is a special numeric value in JavaScript that signals an invalid math result, like dividing zero by zero or parsing a non-numeric string.

Theory

TL;DR

  • NaN stands for "Not-a-Number," yet typeof NaN === "number" — it lives inside the number type
  • Think of it as a poisoned pill: one NaN in a calculation contaminates every result that follows
  • NaN !== NaN is always false. Not a bug, that is the spec
  • Number.isNaN() is the correct check. Global isNaN() coerces strings first and gives wrong answers

Quick example

javascript
console.log(0 / 0); // NaN console.log(typeof NaN); // "number" console.log(NaN === NaN); // false console.log(Number.isNaN(NaN)); // true const result = "abc" * 5; console.log(result + 10); // NaN (propagates)

NaN spreads. Any arithmetic on NaN gives back NaN. That one bad input can ruin a whole chain of calculations with no error thrown.

Why NaN !== NaN

The IEEE 754 floating-point standard defines NaN as "unordered." Two invalid results can come from completely different broken operations: 0/0 and Math.sqrt(-1) are both NaN, but they describe different kinds of invalid math. So the standard says equality with NaN always returns false. This forces you to detect it explicitly rather than accidentally trusting it.

V8 stores NaN as the bit pattern 0x7FF8000000000000. The === operator compares bit patterns, and any comparison involving NaN returns false by spec. No exceptions.

When to use Number.isNaN()

  • Input parsing: check Number.isNaN() before any calculation on user input
  • API responses: replace NaN with null before sending JSON (JSON.stringify converts NaN to null anyway, which can break client math without throwing)
  • Array reductions: filter out NaN before calling .reduce()
  • Anywhere you use global isNaN(): replace it with Number.isNaN()

How JavaScript creates NaN

Invalid numeric operations produce NaN: dividing zero by zero, taking the square root of a negative number, parsing a non-numeric string with Number() or parseInt(). After that, any arithmetic involving NaN automatically produces NaN. The infection is automatic.

Common mistakes

Comparing with ===

javascript
if (result === NaN) { /* this never runs */ }

NaN never equals anything, including itself. Fix: Number.isNaN(result).

Using global isNaN() on strings

javascript
isNaN("hello"); // true (coerced to NaN) isNaN("123abc"); // true (coerced to NaN) isNaN("123"); // false (coerced to 123)

Global isNaN() converts the argument first. It cannot distinguish "this is actually NaN" from "this string does not parse as a number." Use Number.isNaN(Number(value)) when you need both checks.

NaN in JSON

javascript
JSON.stringify({ score: NaN }); // {"score":null}

JSON has no NaN literal. Serialization converts it to null. If your client reads that null and tries to do math, results will be wrong with no error. Sanitize before stringify.

NaN poisoning Math.min / Math.max

javascript
Math.min(1, NaN, 3); // NaN

One NaN poisons the whole aggregate. Filter the array first.

Real-world usage

  • React / Formik: Number.isNaN() in numeric field validators before form submission
  • Express: parse req.query.age with parseInt(), check for NaN before database queries
  • D3.js: filter NaN from chart data arrays before computing scales
  • Lodash: _.isNaN() as a convenience wrapper in utility functions

Follow-up questions

Q: Why does typeof NaN === "number" if NaN is not a valid number?
A: JavaScript's type system follows IEEE 754. NaN is part of the floating-point number space, just an invalid state within it. The type label is technically correct.

Q: What is the difference between isNaN() and Number.isNaN()?
A: Global isNaN() coerces the argument, so isNaN("foo") returns true. Number.isNaN() skips coercion and only returns true for the actual NaN value, so Number.isNaN("foo") returns false.

Q: How do you handle NaN in an array reduce?
A: Filter before reducing: .filter(v => !Number.isNaN(v)). Or guard inside the callback with a fallback value.

Q: What does JSON.stringify do with NaN?
A: It converts NaN to null. JSON has no NaN representation. Always sanitize data before serialization.

Q: (Senior) V8 stores NaN as 0x7FF8000000000000. Why does +NaN === NaN still return false?
A: The unary + returns the same bit pattern. But IEEE 754 specifies that any comparison involving NaN must return false regardless. This is intentional so invalid values cannot accidentally pass equality checks.

Examples

Parsing user input

javascript
const userAge = "25a"; const age = parseInt(userAge, 10); // NaN if (Number.isNaN(age)) { console.log("Invalid age"); // runs } else { console.log(`Age in 5 years: ${age + 5}`); } // Output: "Invalid age"

parseInt stops at the first non-numeric character and returns NaN. Check before you calculate, not after.

Fixing NaN in array reduce

javascript
const prices = ["$10", "20", "abc"]; // Without fix: NaN poisons the sum const broken = prices.reduce((sum, p) => sum + Number(p), 0); console.log(broken); // NaN // With fix: filter invalid values first const total = prices .map(p => Number(p.replace("$", ""))) .filter(v => !Number.isNaN(v)) .reduce((sum, v) => sum + v, 0); console.log(total); // 30

I have seen this exact pattern break production dashboards where one bad API value turned an entire summary widget to NaN. The fix is one line.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?