The Curious Case of NaN: When Numbers Stop Making Sense

The Curious Case of NaN: When Numbers Stop Making Sense
Photo by Nopparuj Lamaikul / Unsplash

In the world of JavaScript, there’s one value that consistently surprises both beginners and seasoned developers alike: NaN. At first glance, it might look like just another value in the Number type. But dig a little deeper, and you’ll realize it’s anything but ordinary.

Let’s start with something that baffles almost everyone:

console.log(NaN === NaN); // false

Wait, what?

How can something not be equal to itself? In every other case in JavaScript, if x === x, it’s true — but NaN breaks that logic.

Why Is NaN Not Equal to Itself?

This isn’t just JavaScript being weird — it’s actually by design, based on the IEEE 754 floating-point standard. JavaScript uses this standard to represent numbers, and in that world:

"NaN is not equal to anything, including itself."

This is because NaN represents an invalid or unrepresentable number. For instance:

  • 0 / 0
  • Math.sqrt(-1)
  • parseInt("not-a-number")

All produce NaN.

Imagine trying to compare two invalid results — should they be equal just because both are invalid? IEEE 754 says no. So JavaScript follows suit.

Then How Do You Check for NaN?

You can't rely on strict or loose equality (=== or ==). Instead, JavaScript gives us a better tool:

Number.isNaN(value); // ✅ Accurate

This function only returns true if the value is actually NaN, and not just some weird coercion like this:

isNaN("abc"); // true (⚠️ misleading)
Number.isNaN("abc"); // false (✅ correct)

So: Always use Number.isNaN for reliability.

But Why is typeof NaN === "number"?

This confuses a lot of people too. If it’s "Not a Number", why is it a number?

Well, NaN is a numeric value, just a special one. It’s still of type "number", because it’s the result of an operation that should yield a number, but failed.

Think of it as:

"It's supposed to be a number, but something went wrong."

It’s like trying to divide by zero and getting a result that’s... well, undefined in math terms.

Real-World Pitfalls of NaN

One of the dangerous aspects of NaN is how it silently breaks logic when not handled properly.

Example: Average Calculator

function average(scores) {
  const sum = scores.reduce((a, b) => a + b, 0);
  return sum / scores.length;
}

average([]); // NaN — because 0 / 0

That may propagate and cause downstream bugs if you forget to check.

Example: Filtering NaN Values

const data = [10, NaN, 15, NaN];
const clean = data.filter(n => !Number.isNaN(n)); // [10, 15]

What About Object.is?

Here’s another lesser-known tip:

Object.is(NaN, NaN); // true

This method can distinguish NaN properly. It’s often used in polyfills or deep equality checks.

In Summary

  • NaN === NaN is false because of IEEE 754 — it’s by design.
  • Use Number.isNaN, not isNaN, to check for true NaN.
  • typeof NaN === "number" because it is a numeric type — just an invalid one.
  • Use Object.is if you really want to compare two NaN values.
  • Always guard against NaN in mathematical logic to avoid silent bugs.

Finally

In a language as quirky as JavaScript, NaN is a reminder that not all "numbers" behave like numbers. It's a symbol of failure in numeric computation — but understanding it helps you write safer, more robust code.

Support Us