JavaScript's “NaN” demystified

Every JavaScript's bashers will troll you with this thing: the NaN === NaN statement is false.

At first glance, this looks like an awful misconception. It's very misleading, and it is always temptful to compare some variable with NaN. I used to think that it was a bad design choice that lead to this.

But I was wrong.

That's true, NaN is an unruly child. But the fact that “NaN is not NaN” is an absolute necessity.

I will try to explain you the reason.

But what is NaN?

NaN stands for “Not A Number”.

Still, typeof NaN is 'number'. More lulz for bashers... ;)

But again, there are some rationale behind that fact.

NaN is produced by some arithmetic operation, when the result is unknown and cannot be represented, even by Infinity.

NaN is used when the result is undefined (e.g. 0/0), or is not a real number (the square root of all negative numbers are imaginary numbers).

Therefore, NaN, as a language feature, IS programmatically a 'number'. That's why typeof NaN === 'number'. But as a mathematical entity, it IS NOT a number.

It MUST be of number type, so it can be autoboxed as an instance ofNumber, and thus have access to all methods of the Number's prototype. It is clear that any arithmetic operator or methods of the Math object should return a Number.

NaN is Not A Number from a mathematical point of view, not from a programming language point of view. Many programming language have a NaN concept, it is not a particularity or a fantasy of the JavaScript language. In fact, NaN is part of the floating-point spec, quoting Wikipedia:

Systematic use of NaNs was introduced by the IEEE 754 floating-point standard in 1985, along with the representation of other non-finite quantities like infinities.

Actually NaN exists in your bare-metal CPU's data representation, it is a special case of the float and of the double type. You have read it: it IS a special case of the float and the double type, that's why JavaScript tells you that typeof NaN === 'number'. Trust JavaScript, it is right!

Why NaN can't compare with itself?

Okey, again that's a question of point of view.

The main trouble comes from the fact that those operators == === != !== have two meanings. The first and immediate meaning is the mathematical equality. However, almost all programming language use the same operator to test equality or identity of any kind of non-numeric instance, e.g. string comparison, object identity, and so on.

NaN !== NaN is choking you, because you read it as an object's instance comparison. But NaN is of number type, so it is the mathematical version of those operators that kicks in there.

Ok, so you are now asking yourself why on earth NaN is different from NaN from a mathematical point of view?

That's pretty simple.

NaN is not a number, it represents something unknown.

Can you tell me how Infinity - Infinity and 0 / 0 compare? Is it really the same value to you? I hope your answer is NO or you need to study the math a bit more.

Moreover, compare Math.sqrt( -1 ) to Math.sqrt( -4 )... Both value are NaN because the square root of a negative number is an imaginary number. In the first case, the Complex Number value is i, in the second case it is 2i. Now I'm sure that you are glad that the JavaScript tells you that Math.sqrt( -1 ) !== Math.sqrt( -4 ) is true.

But then why Math.sqrt( -1 ) !== Math.sqrt( -1 )?

Again, that's logical. We all know how a programming language breaks down big expressions into smaller pieces.

First the left Math.sqrt( -1 ) is evalued and replaced by NaN, then the right Math.sqrt( -1 ) is evalued and replaced by NaN too. Finally the two NaN are compared with each other. At that point, JavaScript cannot tell if the first NaN represent i, 2i or whatever, since like most language, it doesn't have a native type for Imaginary Number. All it has is a comparison of two floating-point numbers, both saying that there are not floating-point numbers anymore.

If you are still confused, understand NaN as an Unknown Number.

NaN is not greater than anything, neither lesser than anything

We know for sure that NaN !== 0 is false.

However, NaN < 0 is false too, as well as NaN > 0.

You can try that for any numbers or Infinity (or even NaN itself), it will be false anyway!

How to deal with NaN

Short answer: use the global isNaN() function.

Better: if you don't have to deal with outdated browsers, use Number.isNaN(). It is more reliable. It is part of ECMAScript 6, a.k.a. Harmony.