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
.
Some examples of expression and their values:
1 / 0 // Infinity
-1 / 0 // -Infinity
0 / 0 // NaN
Infinity / Infinity // NaN
Infinity * 0 // NaN
Infinity - Infinity // NaN
Math.sqrt( -1 ) // NaN
Math.log( -1 ) // NaN
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 of Number
, 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.
You can learn the difference between those two on MDN.
Be aware: in many other programming language, things like a division by zero will throw an exception. JavaScript DO NOT throw any exception for that. The resulting value is simply NaN.
So you have to either check your input or your output, depending on what your code is doing.
You have to check with isNaN()
everytime NaN could be expected, because:
NaN is viral!
Any computation with NaN produces NaN.
Let's look at that method, having in mind that this.a
and value
both equals zero:
MyClass.prototype.unsafe = function( value )
{
this.b = this.a / value ; // Now this.b is NaN
this.c += this.b ; // Now this.c is NaN
this.d = 15 + this.c + this.e * this.g ; // Now this.d is NaN
...
}
As you can see, your whole object will be filled with NaN in no time!
So be careful!
Finally: the good news!
Yes, I have a good news for you: NaN is a falsy value.
So a simple check with if ( myNumber ) { blah() ; }
will avoid it, just like 0 null undefined false '' (...)
.
To be safe, just turn the previous code into that:
MyClass.prototype.safe = function( value )
{
if ( ! value || typeof value !== 'number' )
{
// no division by zero or division by NaN anymore
throw new Error( "Bad argument #0" ) ;
}
this.b = this.a / value ;
this.c += this.b ;
this.d = 15 + this.c + this.e * this.g ;
...
}
On the contrary, Infinity
is a truthy value. Hopefully! ;)