isNaN()
isNaN(value) The global isNaN() function determines whether a value is NaN (Not-a-Number). Unlike Number.isNaN(), the global version coerces its argument to a number before testing.
Syntax
isNaN(value)
Parameters
| Parameter | Type | Description |
|---|---|---|
value | any | The value to check |
Return Value
Returns true if the value is NaN after coercion to a number, false otherwise. The function first converts its argument via the abstract ToNumber operation — the same conversion that Number(value) performs — then evaluates whether the result is NaN.
Examples
Basic Usage
isNaN(NaN); // true
isNaN(0 / 0); // true (produces NaN)
isNaN("hello"); // true (coerced to NaN)
These examples show the straightforward cases — actual NaN values and strings that cannot be parsed. But what about values that coerce to valid numbers even though they are not numbers themselves? That is where things get interesting and the bugs begin to appear.
Values that return false
isNaN(42); // false (42 is a number)
isNaN("42"); // false ("42" coerces to 42)
isNaN(null); // false (null coerces to 0)
isNaN(undefined); // true (undefined coerces to NaN)
isNaN({}); // true (object coerces to NaN)
Notice how null, booleans, and numeric strings pass through cleanly while undefined and objects coerce to NaN. This inconsistency is where most bugs come from — the behaviour depends entirely on JavaScript’s type coercion rules, and few developers memorise every edge case.
The coercion problem
The global isNaN() coerces its argument first, which leads to surprising behavior:
isNaN("hello"); // true — "hello" becomes NaN
isNaN("42"); // false — "42" becomes 42
isNaN(undefined); // true — undefined becomes NaN
isNaN(null); // false — null becomes 0
isNaN(true); // false — true becomes 1
isNaN(false); // false — false becomes 0
The examples above illustrate why global isNaN() catches developers off guard. A string like '42' passes the check even though it is not a number type, while a string like 'hello' fails. If you need to answer the narrower question “is this value exactly NaN?”, there is a better tool available.
Safer alternative: Number.isNaN()
If you need to check for NaN without coercion, use Number.isNaN():
Number.isNaN(NaN); // true
Number.isNaN("hello"); // false (string is not NaN)
Number.isNaN(undefined); // false
Number.isNaN({}); // false (object is not NaN)
Even with its coercion quirks, isNaN() can still work for basic form validation where you want to accept strings that look like numbers. The next example shows a lenient check that treats both 21 and '42' as valid numeric input.
Practical example: input validation
When validating user input that should be a number:
function processNumber(input) {
if (isNaN(input)) {
return "Please enter a valid number";
}
return input * 2;
}
processNumber("hello"); // "Please enter a valid number"
processNumber("42"); // 84 (coerced)
processNumber(21); // 42
The lenient approach above accepts strings like '42', but sometimes you want to reject anything that is not already a number. For that, combine a typeof guard with Number.isNaN() to catch both type mismatches and actual NaN values, as shown in the stricter function below:
function strictNumberCheck(input) {
if (typeof input !== "number" || Number.isNaN(input)) {
return "Not a valid number type";
}
return input * 2;
}
strictNumberCheck("42"); // "Not a valid number type"
strictNumberCheck(21); // 42
strictNumberCheck(NaN); // "Not a valid number type"
Parameters
| Parameter | Type | Description |
|---|---|---|
value | any | The value to test. Coerced to number before the NaN check. |
How global isNaN() works
The global isNaN(value) function first converts its argument to a number using the abstract ToNumber operation — the same conversion that Number(value) performs. If the result of that conversion is NaN, the function returns true; otherwise it returns false. Because string-to-number conversion fails for non-numeric strings, this means isNaN('abc') returns true even though 'abc' is a perfectly valid string, not a NaN value.
Prefer Number.isNaN() in modern code
The global isNaN() exists for historical reasons and its coercion behaviour is a known source of bugs. In all new code, prefer Number.isNaN(), which returns true only for the actual NaN value and never coerces. The difference matters when checking variables that might hold strings, booleans, or other non-numeric values:
// Unintended: global isNaN returns true for strings it cannot parse
isNaN('not a number'); // true
// Correct: Number.isNaN is strict
Number.isNaN('not a number'); // false — it's a string, not NaN
The coercion chain
When isNaN('value') is called, JavaScript internally runs Number('value'), and then checks whether the result equals NaN. This is equivalent to Number.isNaN(Number(value)). Understanding this two-step process explains all the surprising results — isNaN(null) is false because Number(null) is 0, and isNaN('') is false because Number('') is 0.
When global isNaN() Still Fits
The global isNaN() function still has a place when you deliberately want loose numeric checking. That can be useful in legacy code or quick validation paths where strings such as "42" should count as valid input after conversion. In those cases, the coercion is part of the intended behavior rather than a mistake.
The tradeoff is that the same coercion can hide mistakes. If a value might be a string, boolean, or object, isNaN() can return false for something that is not actually a number. When that distinction matters, Number.isNaN() is the safer check because it only accepts the real NaN value.
When to Use global isNaN()
The global isNaN() function is mostly useful when you intentionally want coercion as part of the check. That can be handy in quick validation code or legacy code that already treats strings like numeric input. In new code, though, Number.isNaN() is usually clearer because it distinguishes the actual NaN value from values that merely become NaN after conversion.
See Also
Number.isNaN()— Checks for NaN without argument coercionNumber.isFinite()— Checks if a value is a finite numberparseFloat()— Parses a string and returns a floating-point numberparseInt()— Parses a string and returns an integer