isNaN()
Tests whether a value becomes NaN after being coerced to a number.
isNaN(value)- Added in JavaScript ECMAScript 1 (1997)
Parameters
| Parameter | Type | Description |
|---|---|---|
$value | any | The value to be tested. It is converted to a number before the test. |
Return value
booleantrue if the value is NaN after conversion to a number; otherwise false.
Errors
Throws TypeError if the value is a BigInt or a Symbol, since neither can be converted to a number.
Changelog
- PHP ECMAScript 2015Number.isNaN() was added as the non-coercing alternative and is the preferred check in new code.
isNaN() does not answer "is this value NaN". It answers "would Number(value) be NaN", which is a different and much broader question. That is why isNaN("abc") is true even though the string "abc" is not the NaN value, and why isNaN(undefined) is true while isNaN(null) is false.
Which one you actually want
- To detect the NaN value itself, use
Number.isNaN(x), or the identity trickx !== x, which is true only for NaN. - To decide whether an arbitrary value parses as a number, the coercion in
isNaN()is exactly what you want — but write the intent out asNumber.isNaN(Number(x))so the next reader is not left guessing.
The coercion table people trip on
Empty strings, whitespace-only strings, null, false, empty arrays and single-element numeric arrays all convert to a number cleanly, so isNaN() returns false for every one of them. Passing a BigInt or a Symbol throws a TypeError rather than returning true, which can crash a validation path that assumed the function was total.
Example
When to use it
- Reject a user-entered string that does not parse as a number at all.
- Guard an arithmetic result before writing it to a total or an average.
- Check whether a parsed date or measurement came back as NaN before formatting it.
Frequently asked questions
Why is isNaN('abc') true when 'abc' is a string, not NaN?
Because isNaN converts its argument to a number first, and Number("abc") is NaN. Use Number.isNaN("abc"), which returns false, if you want to test for the NaN value itself.
Should I use isNaN or Number.isNaN?
Use Number.isNaN in new code — it tests for the NaN value with no coercion and never throws. Reach for the global isNaN only when you deliberately want the "does this coerce to a number" behaviour, and even then Number.isNaN(Number(x)) states it more clearly.
Why does NaN === NaN return false?
IEEE 754 defines NaN as unequal to every value including itself, so no equality operator can detect it. That is precisely why Number.isNaN, Object.is and the x !== x idiom exist.
More examples
isNaN versus Number.isNaN
Number.isNaN is true for exactly one entry — the NaN value. The global isNaN is additionally true for "NaN", undefined and {}, because those coerce to NaN.
const values = [NaN, "NaN", "42", "", null, undefined, true, [], {}];
for (const v of values) {
console.log(
JSON.stringify(v) ?? String(v),
"| isNaN:", isNaN(v),
"| Number.isNaN:", Number.isNaN(v),
);
}Why NaN needs a function at all
Equality operators can never find NaN, so indexOf misses it while includes finds it. Object.is and x !== x are the two reliable identity checks.
const x = 0 / 0;
console.log(x === NaN); // false — NaN equals nothing, itself included
console.log(x !== x); // true — the classic self-inequality test
console.log(Object.is(x, NaN)); // true
console.log([NaN].includes(NaN)); // true — includes uses SameValueZero
console.log([NaN].indexOf(NaN)); // -1 — indexOf uses ===A validation helper that says what it means
Explicit handling of the blank-string case is what the global isNaN silently skips. The last two lines show that null still slips through as 0 unless you reject it by type as well.
function toNumber(input) {
if (typeof input === "string" && input.trim() === "") return null;
const n = Number(input);
return Number.isNaN(n) ? null : n;
}
console.log(toNumber("42")); // 42
console.log(toNumber(" ")); // null — blank handled explicitly
console.log(toNumber("abc")); // null
console.log(toNumber(null)); // null? no — Number(null) is 0
console.log(toNumber(null)); // 0
Discussion