In JavaScript:
NaN === NaN // false
NaN !== NaN // true
NaN is the only value in JavaScript that doesn't equal itself. This follows the IEEE 754 floating-point standard, but it's counterintuitive.
What Is NaN?
NaN represents an invalid numeric result:
Math.sqrt(-1) // NaN (no real square root of negative)
parseInt('abc') // NaN (can't parse non-numeric string)
0 / 0 // NaN (mathematically undefined)
Infinity - Infinity // NaN
Any operation that can't produce a valid number returns NaN.
Why NaN !== NaN
The IEEE 754 standard defines NaN as not equal to anything, including itself. The reasoning: NaN represents an unknown or invalid value. Two unknown values can't be assumed equal.
const x = 0 / 0; // NaN
const y = 0 / 0; // NaN
x === y; // false - different operations, different unknowns
From a mathematical perspective, comparing undefined values doesn't make sense.
Checking for NaN
Since value === NaN doesn't work, use Number.isNaN():
Number.isNaN(NaN) // true
Number.isNaN(0 / 0) // true
Number.isNaN('abc') // false (string, not NaN)
Number.isNaN(undefined) // false
Or use the self-inequality property:
function isNaNValue(value) {
return value !== value;
}
isNaNValue(NaN) // true
This works because NaN is the only value that doesn't equal itself.
isNaN() vs Number.isNaN()
JavaScript has two NaN-checking functions:
isNaN() - coerces to number first:
isNaN('abc') // true (coerces to NaN)
isNaN('123') // false (coerces to 123)
isNaN(undefined) // true (coerces to NaN)
isNaN({}) // true (coerces to NaN)
Number.isNaN() - no coercion, checks actual NaN:
Number.isNaN('abc') // false (string, not NaN)
Number.isNaN('123') // false
Number.isNaN(undefined) // false
Number.isNaN({}) // false
Number.isNaN(NaN) // true
Use Number.isNaN() for reliable NaN detection. isNaN() is misleading.
How NaN Propagates
Operations with NaN produce NaN:
NaN + 5 // NaN
NaN * 2 // NaN
NaN / 10 // NaN
Math.max(1, NaN) // NaN
This is "NaN poisoning"—one NaN corrupts the entire calculation:
function average(numbers) {
const sum = numbers.reduce((a, b) => a + b, 0);
return sum / numbers.length;
}
average([1, 2, NaN, 4]); // NaN
A single NaN makes the average NaN.
Checking for Numeric Values
To verify a value is a valid number:
function isValidNumber(value) {
return typeof value === 'number' && !Number.isNaN(value);
}
isValidNumber(123) // true
isValidNumber(NaN) // false
isValidNumber('123') // false (string)
isValidNumber(Infinity) // true
For finite numbers only:
Number.isFinite(123) // true
Number.isFinite(Infinity) // false
Number.isFinite(NaN) // false
Number.isFinite('123') // false (no coercion)
Common Sources of NaN
Parsing invalid input:
parseInt('abc') // NaN
parseFloat('xyz') // NaN
Number('not a number') // NaN
Math operations with non-numbers:
'string' * 2 // NaN
undefined + 5 // NaN
{} - 10 // NaN
Invalid math operations:
Math.sqrt(-1) // NaN
0 / 0 // NaN
Infinity / Infinity // NaN
Avoiding NaN in Calculations
Validate input:
function safeDivide(a, b) {
if (b === 0) return null; // Or throw error
return a / b;
}
Provide defaults:
const value = parseFloat(input) || 0;
Filter out NaN values:
const numbers = [1, 2, NaN, 4, NaN, 5];
const valid = numbers.filter(n => !Number.isNaN(n));
// [1, 2, 4, 5]
NaN in Comparisons
NaN is neither greater than nor less than any value:
NaN > 5 // false
NaN < 5 // false
NaN >= 5 // false
NaN <= 5 // false
Sorting arrays with NaN can produce unexpected results:
[1, NaN, 3, 2].sort((a, b) => a - b);
// NaN comparisons return NaN, breaking sort
Filter NaN before sorting or handle in comparator:
function compare(a, b) {
if (Number.isNaN(a)) return 1; // Push NaN to end
if (Number.isNaN(b)) return -1;
return a - b;
}
[1, NaN, 3, 2].sort(compare); // [1, 2, 3, NaN]
typeof NaN
Despite being "Not-a-Number," typeof NaN is 'number':
typeof NaN // 'number'
This is because NaN is a numeric type representing an invalid number—it's still part of the number type system.
Object.is and NaN
Object.is() treats NaN specially:
Object.is(NaN, NaN) // true
NaN === NaN // false
Object.is() uses "same-value equality," which considers NaN equal to itself. This is useful for certain algorithms.
Returning NaN from Functions
Returning NaN signals invalid input or computation failure:
function parseAge(input) {
const age = parseInt(input);
if (Number.isNaN(age) || age < 0 || age > 150) {
return NaN;
}
return age;
}
But consider if null or throwing an error is clearer.
JSON and NaN
JSON doesn't support NaN. It becomes null when serialized:
JSON.stringify({ value: NaN }) // '{"value":null}'
Deserializing gives null, not NaN. Handle this if you need to preserve NaN through serialization.
Performance
Checking value !== value is slightly faster than Number.isNaN(value), but the difference is negligible. Use Number.isNaN() for clarity.
Historical Context
The global isNaN() predates ES6. Its coercion behavior surprised developers. Number.isNaN() was added in ES6 to provide predictable behavior without coercion.
Further Reading
MDN's NaN documentation covers all behaviors and edge cases.
The IEEE 754 standard explains why NaN doesn't equal itself in floating-point arithmetic.
Axel Rauschmayer's post on NaN and Infinity explores JavaScript's special numeric values.
NaN's self-inequality is one of JavaScript's most notorious quirks.
0 comments