Dealing with NaN in JavaScript

I believe we, developers, have all experienced a few confusing moments while developing in JavaScript. Dealing with NaN seems to be one of them.

Trying to hide from weird JS concepts

MDN defines NaN as being a global property that represents Not-a-Number. With the typeof operator, we can check that NaN is of the primitive Data Type Number.

typeof NaN; //"number"
typeof 0; //"number"

Usually, we have to deal with NaN when Math functions fail or when trying to parse a number fails, like shown below.

Math.round('a'); //NaN
parseInt('b'); //NaN

Well, so far everything seems ok. However, how do we know if a returned value is NaN? As we saw previously, typeof NaN is of Number, but typeof 0 is also of Number. This means that the operator typeof won't tell us specifically if the value we're checking is NaN.

typeof NaN === "number"; //true
typeof 0 === "number"; //true

So, if we can't use the operator typeof, what can we do to check if a value is NaN? The answer to this question may seem very simple. Why don't we compare the returned value to NaN. If it is NaN we'll get true, otherwise we'll get false and know that it isn't NaN. Let's try:

Math.round('a') == NaN; // false

Wait. What? But… we know that Math.round('a') results in NaN. How can NaN == NaN return false?

NaN is the only value in JavaScript that when compared to itself returns false. As weird as it seems, at least now we have a way to identify when a value is NaN.

let roundNum = Math.round('a'); // roundNum is assigned NaN
roundNum == roundNum; // false
let roundNum2 = Math.round(1.3); // roundNum2 is assigned 1
roundNum2 == roundNum2; // true

Yes, I know this is very confusing, but bare with me. In the example above, roundNum is NaN because when we compare roundNum for equality with itself, the result is false. As we learned before, that only happens with NaN. In the second case, roundNum2 isn't NaN, because when compared to itself the result was true.

isNaN()

As it turns out, JavaScript has a function that helps us identify when a value is NaN. Well, let's try it out!

isNaN('lalala'); // true
isNaN(' '); // false

You may be confused again. 'lalala' and ' ' are both strings. Why is the former considered NaN and the latter not? One thing to pay attention to is that, depending on the input type, the function will try to use coercion and then check if the coerced value is NaN. It sort of looks like this:

function isNaN(arg) {
let coercedValue = Number(arg);
return coercedValue != coercedValue;
}
// This is what really happens under the hood
// isNaN('lalala') -> Number('lalala') -> NaN => (NaN != NaN) ->true
// isNaN(' ') -> Number(' ') -> 0 -> (0 != 0) -> false

Also, remember that you are checking if a certain value is NaN, which does not simply mean “this value is not a number”. It specifically means “this value is a numeric Not-a-Number value according to IEEE-754”.

Number.isNaN()

This is a relatively new feature specified in ECMAScript 2015 (ES6) and brings one major difference from the regular isNaN(): the argument doesn't get forcefully coerced. This means that this function now compares if the value passed (as is) is NaN.

isNaN('lalala'); // true
Number.isNaN('lalala'); // false

What happens here is that in the first case, the function isNaN() tries to forcefully coerce 'lalala' into a number. As a result of a failed calculation, NaN is returned and then it is checked against NaN, returning true.

However, in the second case, the function Number.isNaN() doesn't try to forcefully convert the parameter to a number. Instead, it simply checks whether the input value is NaN or not.

Conclusion

This topic can get very confusing, but overall remember that NaN is a value of type Number; it usually appears when a Math method calculation fails, and its comparison to itself is false (NaN == NaN = false). There's a function called isNaN() that coerces the parameter to a number before comparing against NaN. To have a more robust solution, ES6 brought in Number.isNaN() that returns whether a parameter is NaN without going through any forceful coercion.

Finally, if you'd like to check if a certain value "is not a number" instead of NaN, don't use isNaN(), simply use typeof variable !== 'number'.

Hope this was useful. Happy coding! :)