NaN, not a number, is a special type value used to denote an unrepresentable value. With JavaScript, NaN
can cause some confusion, starting from its typeof
and all to the way the comparison is handled.
Several operations can lead to NaN
as the result. Here are some examples (follow along on JSBin: jsbin.com/yulef):
Math.sqrt(-2) Math.log(-1) 0/0 parseFloat('foo') |
The first trap for many JavaScript beginners is usually the unexpected result of calling typeof
:
console.log(typeof NaN); // 'number' |
In a way, while NaN isn’t supposed to be a number, its type is number. Got it?
Stay calm, as this will continue to lead to many confusing paths. Let’s compare two NaNs:
var x = Math.sqrt(-2); var y = Math.log(-1); console.log(x == y); // false |
Maybe that’s because we’re supposed to use strict equal (===) operator instead? Apparently not.
var x = Math.sqrt(-2); var y = Math.log(-1); console.log(x === y); // false |
Arrgh! Could it be because they are NaNs from two different operations? What about…
var x = Math.sqrt(-2); var y = Math.sqrt(-2); console.log(x == y); // false |
Even crazier:
var x = Math.sqrt(-2); console.log(x == x); // false |
What about comparing two real NaNs?
console.log(NaN === NaN); // false |
Because there are many ways to represent a NaN, it makes sense that one NaN will not be equal to another NaN. Still, this is the reason why I sometimes tweet:
To solve this, originally I intended to submit this proposal for ECMAScript 7:
But of course, solutions (and workarounds) already exist today.
Let’s get to know the global function isNaN:
console.log(isNaN(NaN)); // true |
Alas, isNan()
has its own well-known flaws:
console.log(isNaN('hello')); // true console.log(isNaN(['x'])); // true console.log(isNaN({})); // true |
This often leads to a number of different workarounds. One example is to exploit the non-reflective nature of NaN (see e.g. Kit Cambridge’s note):
var My = { isNaN: function (x) { return x !== x; } } |
Another example is to check for the value’s type first (to prevent coercion):
My.isNaN = function(x) { return typeof x === 'number' && isNaN(x)}; |
Fortunately, for the upcoming ECMAScript 6, there is Number.isNaN()
which provides a true NaN
detection (BTW, you can already use this function in the latest version of Chrome and Firefox). In the latest draft from April 2014 (Rev 24), this is specified in Section 20.1.2.4:
When the Number.isNaN is called with one argument number, the following steps are taken:
1. If Type(number) is not Number, return false.
2. If number is NaN, return true.
3. Otherwise, return false.
In other words, it returns true
only if the argument is really NaN:
console.log(Number.isNaN(NaN)); // true console.log(Number.isNaN(Math.sqrt(-2))); // true console.log(Number.isNaN('hello')); // false console.log(Number.isNaN(['x'])); // false console.log(Number.isNaN({})); // false |
Next time you need to deal with NaN, be extremely careful!