NaN
Represents the IEEE 754 Not-a-Number value, the only value that compares unequal to itself.
NaN- Added in JavaScript Baseline widely available since July 2015
Return value
numberThe Not-a-Number value. It is of type number despite the name.
Errors
Assigning to NaN throws a TypeError in strict mode, because the global property is non-writable and non-configurable.
Changelog
- PHP ES5The global NaN property became non-writable and non-configurable. In older engines it could be reassigned, so defensive code sometimes captured it in a local variable.
NaN is a property of the global object holding the IEEE 754 "Not a Number" value. You get one from a failed conversion (Number("12px"), parseInt("blabla")), from a mathematically undefined result (Math.sqrt(-1), 0 / 0, Infinity / Infinity), from an invalid date's getTime(), and from any arithmetic that touches an existing NaN. It is contagious, so one bad field can poison an entire calculation before you notice.
Testing for it
The rule worth memorising: this is the only value in JavaScript that is not equal to itself. x === NaN is always false, so equality can never detect it. Use Number.isNaN(x), which is true only for the real value, or Object.is(x, NaN). The older global isNaN(x) coerces its argument first, so isNaN("hello") is true even though a string is not NaN — reach for the Number version unless you actually want coercion.
Where self-inequality leaks out
Ordered comparisons (<, >, >=, <=) against it are all false, which quietly breaks sorting and range checks. indexOf uses strict equality and will never find it, while includes, Set and Map keys use SameValueZero and will. typeof NaN is "number", it is falsy, and JSON.stringify serialises it as null.
Example
When to use it
- Detecting that user input failed to parse as a number before storing it
- Guarding an average or sum so one unparseable row does not turn the whole total into NaN
- Validating that a constructed Date is real by checking getTime()
- Choosing between includes() and indexOf() when an array may hold NaN
Frequently asked questions
Why does NaN === NaN return false?
Because IEEE 754 defines NaN as unordered and unequal to every value including itself, and JavaScript follows that specification exactly. NaN means "the result of this operation is not a meaningful number", and two separately failed operations are not claimed to have produced the same answer. Use Number.isNaN() or Object.is() when you need to test for it.
What is the difference between isNaN() and Number.isNaN()?
The global isNaN() coerces its argument to a number before testing, while Number.isNaN() returns true only when the argument already is the NaN value. That is why isNaN("hello") and isNaN(undefined) are both true but Number.isNaN() reports false for both. Use Number.isNaN() unless you deliberately want the coercion.
How do I check if a value is NaN?
Call Number.isNaN(value), or use Object.is(value, NaN) if you prefer. The self-inequality trick value !== value also works and is what older polyfills used. Never compare with === or ==, because both always return false against NaN.
More examples
Number.isNaN() versus the global isNaN()
The global isNaN() converts its argument to a number first, so the string "hello" and undefined both report true even though neither is NaN. Number.isNaN() skips the conversion and answers only for the actual NaN value, which is almost always what you want in a validation check.
const values = [NaN, "hello", undefined, "42", null, ""];
for (const v of values) {
console.log(
JSON.stringify(v),
"| isNaN:", isNaN(v),
"| Number.isNaN:", Number.isNaN(v),
);
}NaN spreading through a calculation
The first total is NaN because a single unconvertible string contaminates the running sum. Filtering with Number.isNaN() before reducing keeps the two valid prices and produces 17.5.
const rows = [{ price: "10" }, { price: "7.5" }, { price: "n/a" }];
const total = rows.reduce((sum, r) => sum + Number(r.price), 0);
console.log("naive total:", total); // NaN - one bad row poisons everything
const clean = rows
.map((r) => Number(r.price))
.filter((n) => !Number.isNaN(n));
console.log("kept:", clean);
console.log("safe total:", clean.reduce((a, b) => a + b, 0));NaN as a Set member and Map key
Set and Map compare keys with SameValueZero, which treats every NaN as one value, so four separate NaN expressions collapse into a single Set entry and a Map lookup succeeds. Direct === comparison still reports false.
const set = new Set([NaN, NaN, 0 / 0, Number("x")]);
console.log("set size:", set.size); // 1 - all four are the same value
console.log("has NaN:", set.has(NaN)); // true
const map = new Map([[NaN, "stored"]]);
console.log("map lookup:", map.get(NaN)); // "stored"
console.log("but plain equality:", NaN === NaN); // false
Discussion