Skip to main content

NaN Is the Only JavaScript Value That Is Not Equal to Itself

Open a console and type NaN === NaN. The answer is false. Not a quirk of one engine, not a bug in the interpreter: the language is required to behave this way, and every mainstream runtime does. For a developer who thinks of equality as the simplest operation in programming, that result is a small shock, and then it becomes a useful mental model once you know where it comes from.

The origin is the IEEE 754 floating point standard. NaN, which stands for Not a Number, was introduced there in 1985 as a systematic way to represent undefined numeric results such as the outcome of zero divided by zero. The standard also specifies how comparisons must behave when one operand is not a real number. A comparison of two ordinary numbers has three possible outcomes: less than, equal, or greater than. NaN breaks that trichotomy and introduces a fourth relation, unordered. For any unordered comparison, the predicates tied to the mathematical symbols return false. So NaN smaller than x is false, NaN greater than x is false, and NaN equals x is false as well. Inequality is the exception: NaN not equal to x returns true, because it is defined as the logical negation of the equality test. Applying that rule to NaN itself gives the result you see in the console.

That single rule produces a handful of behaviours that show up in real code far more often than people expect. A few of them I checked directly in a Node.js REPL, and they are worth memorising. Comparing NaN to NaN with strict equality returns false, while Object.is(NaN, NaN) returns true, because Object.is implements SameValue rather than the equality predicate. The typeof operator still reports number, which is why a NaN value can quietly flow through numeric APIs that only do a typeof check. JSON.stringify turns NaN into null, so a NaN that escapes into an API response silently becomes a missing value on the other side of the wire, and a client that expects a number gets a null it never guarded against.

Searching for NaN has its own trap. Array.prototype.indexOf uses strict equality, so it can never find NaN and returns negative one. Array.prototype.includes uses a different comparison called SameValueZero, so it finds NaN without complaint. A Set or a Map handles NaN as a key correctly, and a Set that receives NaN twice keeps a single entry, because SameValueZero treats the two values as the same key. Then there is sorting: an array that mixes numbers with NaN gets an ordering that is effectively unpredictable, because none of the comparisons used by the sort algorithm can establish a real order for that element. These are not obscure edge cases. They are the reason defensive code around numeric input exists at all.

The most useful habit is the simplest one. Never write a direct comparison against NaN. Instead of checking whether a value equals NaN, check whether the value is not equal to itself, or better, use Number.isNaN, which was added in ES2015 and does no type coercion. The older global isNaN converts its argument first, which makes it report true for all kinds of non numeric input: isNaN of a string reports true even though the string is not the NaN value at all. Number.isNaN reports false for that same string and true only for an actual NaN. That difference alone has caused a lot of validation bugs.

It is also worth remembering why NaN exists at all. A quiet NaN propagates through arithmetic instead of throwing, so a calculation pipeline can complete and let you detect the failure at the end rather than checking every intermediate step. That is genuinely convenient. The cost is that a NaN can travel a long way from its origin before anyone notices, and the moment it reaches a serialisation boundary or a comparison, it behaves unlike every other value in the language. Treat NaN as a signal that an upstream computation failed, find where it entered your data, and fix that, rather than sprinkling equality checks through the code until the symptom disappears.

We use cookies for ads and analytics.