Why is isNaN(null) == false in JS?
Solution 1
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 NaN
2. 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.
Solution 2
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.
Solution 3
(My other comment takes a practical approach. Here's the theoretical side.)
I looked up the ECMA 262 standard, which is what Javascript implements. Their specification for isNan:
Applies ToNumber to its argument, then returns true if the result is NaN, and otherwise returns false.
Section 9.3 specifies the behavior of ToNumber
(which is not a callable function, but rather a component of the type conversion system). To summarize the table, certain input types can produce a NaN. These are type undefined
, type number
(but only the value NaN
), any object whose primitive representation is NaN
, and any string
that cannot be parsed. This leaves undefined
, NaN
, new Number(NaN)
, and most strings.
Any such input that produces NaN
as an output when passed to ToNumber
will produce a true
when fed to isNaN
. Since null
can successfully be converted to a number, it does not produce true
.
And that is why.
Solution 4
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
Solution 5
Null is not NaN, as well as a string is not NaN. isNaN() just test if you really have the NaN object.
Related videos on Youtube

Hanno Fietz
I'm a (mostly) backend programmer, the majority of my work I do in PHP and Java, typically with a Postgres database. I really like Javascript as a language, but I'm sceptical about the modern JS frameworks, I sometimes wonder if I'm just getting too old for that kind of thing? ;) I'm being very very unfair to Python by using it most of the time for admin scripts and cronjobs instead of "real" software. Things that have made my professional life a happier one over the years include PHP 7, and Joda Time, and Guava. Also, git and JIRA, and JSON, and new Postgres versions, and UTF-8. And coffee.
Updated on February 08, 2022Comments
-
Hanno Fietz 10 months
This code in JS gives me a popup saying "i think null is a number", which I find slightly disturbing. What am I missing?
if (isNaN(null)) { alert("null is not a number"); } else { alert("i think null is a number"); }
I'm using Firefox 3. Is that a browser bug?
Other tests:
console.log(null == NaN); // false console.log(isNaN("text")); // true console.log(NaN == "text"); // false
So, the problem seems not to be an exact comparison with NaN?
Edit: Now the question has been answered, I have cleaned up my post to have a better version for the archive. However, this renders some comments and even some answers a little incomprehensible. Don't blame their authors. Among the things I changed was:
- Removed a note saying that I had screwed up the headline in the first place by reverting its meaning
- Earlier answers showed that I didn't state clearly enough why I thought the behaviour was weird, so I added the examples that check a string and do a manual comparison.
-
Matt Rogish about 14 yearsdon't you mean "Why is isNaN(null) == false" ?
-
devinmoore about 14 yearsBased on your code, isnan(null) is returning false (null is not "not a number") if it says "I think null is a number".
-
Sebastian Simon over 1 yearUse
Number.isNaN
instead.
-
Hanno Fietz about 14 yearsBut then at least a string is cast into a NaN object, as isNaN("text") returns true.
-
nilfalse over 9 yearsBTW,
NaN !== NaN
. So, I think, it is not totally correct to sayNumber('abcd') == NaN
becauseNumber('abcd')
isNaN
but not equal toNaN
. I adore JavaScript. -
Glenn Moss over 9 yearsYes. I meant to convey that
Number('abcd')
isNaN
but I implied that it tests true for equality, which is not the case. I will edit it. -
timidboy over 8 yearsI wonder why are
isNaN
andNumber
designed to behave that way? -
Glenn Moss over 8 yearsThe simple answer is that it's designed to have the same semantics as the IEEE 754 floating-point standard.
-
iatboy almost 8 yearsSince
null
is converted to0
, whynull == false
returns false? -
Glenn Moss almost 8 yearsThe conversion of
null
to0
only (at least in this context) occurs within theisNaN()
function, which coerces its argument. -
divesh premdeep almost 8 yearsWon't work if
myInt
="123d".parseInt
converts "123d" to 123, which then fails theisNaN
test. -
guy mograbi almost 8 yearsindeed, If you want to catch that scenario as well, I suggest to combine my answer and Glenn's. which will look like this
isNaN(parseInt(str,10)) || isNaN(Number())
. btw - for me, since I have to runparseInt
in order to use the numeric value of the string, allowing "123d" to be considered as valid number is fine. However I see the need to detect that scenario as well. -
JoshBerke about 7 yearsNumber(null) == 0 but parseInt(null) == NaN love JS
-
Lynn over 6 yearsNote that
isNaN(undefined) === true
. -
Bekim Bacaj almost 6 yearsWhat do you imagine that NaN should mean? What do you think is so misleading about NaN or in testing for it? Why are you disturbed?
-
Adam almost 6 yearsWell, this was 8 years ago, but it looks like it I was disturbed that 1) it has inconsistent results for values that aren't of type Number, and 2) it ever returns true for something that isn't of type Number. Because a string is not, in fact, a NaN. (Also see my other answer, which explains why this happens.)
-
Sebastian Simon over 1 year@JoshBerke
parseInt
accepts strings;String(null)
is"null"
, which doesn’t start with digits or whitespace followed by digits.parseInt
andNumber
are very different functions. -
Sebastian Simon over 1 year“isNaN() just test if you really have the NaN object” — No,
Number.isNaN
does that.isNaN
coerces its argument to a number, then checks if it is aNaN
value.