Why is isNaN(null) == false in JS?

I believe the code is trying to ask, "is x numeric?" with the specific case here of x = null. The function isNaN() can be used to answer this question, but semantically it's referring specifically to the value NaN. From Wikipedia for NaN:

NaN (Not a Number) is a value of the numeric data type representing an undefined or unrepresentable value, especially in floating-point calculations.

In most cases we think the answer to "is null numeric?" should be no. However, isNaN(null) == false is semantically correct, because null is not NaN.

Here's the algorithmic explanation:

The function isNaN(x) attempts to convert the passed parameter to a number1 (equivalent to Number(x)) and then tests if the value is NaN. If the parameter can't be converted to a number, Number(x) will return NaN2. Therefore, if the conversion of parameter x to a number results in NaN, it returns true; otherwise, it returns false.

So in the specific case x = null, null is converted to the number 0, (try evaluating Number(null) and see that it returns 0,) and isNaN(0) returns false. A string that is only digits can be converted to a number and isNaN also returns false. A string (e.g. 'abcd') that cannot be converted to a number will cause isNaN('abcd') to return true, specifically because Number('abcd') returns NaN.

In addition to these apparent edge cases are the standard numerical reasons for returning NaN like 0/0.

As for the seemingly inconsistent tests for equality shown in the question, the behavior of NaN is specified such that any comparison x == NaN is false, regardless of the other operand, including NaN itself1.


I just ran into this issue myself.

For me, the best way to use isNaN is like so

isNaN(parseInt(myInt))

taking phyzome's example from above,

var x = [undefined, NaN,     'blah', 0/0,  null, 0,     '0',   1,     1/0, -1/0,  Number(5)]
x.map( function(n){ return isNaN(parseInt(n))})
        [true,      true,    true,   true, true, false, false, false, true, true, false]

( I aligned the result according to the input, hope it makes it easier to read. )

This seems better to me.


This is indeed disturbing. Here is an array of values that I tested:

var x = [undefined, NaN, 'blah', 0/0, null, 0, '0', 1, 1/0, -1/0, Number(5)]

It evaluates (in the Firebug console) to:

,NaN,blah,NaN,,0,0,1,Infinity,-Infinity,5

When I call x.map(isNaN) (to call isNaN on each value), I get:

true,true,true,true,false,false,false,false,false,false,false

In conclusion, isNaN looks pretty useless! (Edit: Except it turns out isNaN is only defined over Number, in which case it works just fine -- just with a misleading name.)

Incidentally, here are the types of those values:

x.map(function(n){return typeof n})
-> undefined,number,string,number,object,number,string,number,number,number,number

Tags:

Javascript