Better NaN check with ES6 Number.isNaN
By: Samantha Ming
Tags: JavaScript, Javascript Tips, Software Development, Front End Development, Programming

CodeTidbit by SamanthaMing.com

The isNaN check in JS always had its issue - it returns true for a value that isn’t actually a number 😱. Why? because it coerces the value to a number first, which can falsely result to a NaN . ES6 to the rescue! Number.isNaN won't forcefully do the conversion. Which means only values of the type number will return true. Yay 👏

// What?? 😱

isNaN('string') // true // Better ✅

Number.isNaN('string') // false

I’m confused…

Wait, shouldn’t the NaN check return true for a string and false for a number? NaN means “not a number”, so shouldn’t it be checking for something being “not a number”. I’m so confused

☝️ If you’re one of these people. Don’t worry, I was too! Let me try to demystify this for you.

Number.isNaN vs isNaN

Let’s try to understand what these two methods are doing.

isNaN

Returns true if the argument coerces to NaN, otherwise returns false.

Standard ECMA-262: 5.1 edition

So this method will first coerce the argument using, for instance, Number(argument) , and if it evaluates to NaN , it will return true.

Number.isNaN

Determines whether the argument is NaN and its type is Number.

Standard ECMA-262: 6th edition

There is no coercion here. It does 2 things:

First, it checks the type using, for instance, typeof (argument) , and if it doesn't evaluate to number , it will return false.

, and if it doesn't evaluate to , it will return false. Second, it will check if the argument has the value NaN , if so, it will return true.

Summary

Just to be super clear, the difference between these 2 methods is that Number.isNaN doesn't coerce or forcefully convert the argument to a Number before determining whether it has the value NaN .

Understanding NaN

Alright, let’s move on to understanding what NaN is. It stands for "not a number". But I think this is the source of the problem. If you think of it in its literal term, you might interpret it as whatever is "not a number", then it must be NaN . This is incorrect. It's not the opposite of a number. Take, for instance, a "string". Sure, it's "not a number" but it doesn't evaluate to NaN . So "string" is not NaN 🙅‍♀️

It would be much more accurate to think of NaN as being “invalid number”, “failed number,” or even “bad number,” than to think of it as “not a number.”

Kyle Simpson, You Don’t Know JS

So NaN is an invalid number. You get NaN when you try to do some mathematical operations on values that are not Numbers.

const invalid = 100 // "string"; console.log(invalid); // NaN

Tips to understanding NaN

Another way that helped me understand this, is thinking NaN as its own value. Just like how 200 is a value, NaN is also its own value. Refrain from referring it in its literal term of, "not a number", just pronounce it as one word, nan. That way your brain won't think of it as "not a number".

Alright moving forward, we will stop referring NaN as "not a number", it's just another value and this value is called NaN . Trust me, when you do this, it will help ease a lot of confusion 🙆‍♀️.

Problem Checking NaN

So why do we need a method to check for NaN . Why does this method isNaN even exist? Well, it exists because there is no easy for us to check if a value is NaN . That's because NaN doesn't equal itself. So we can't simply compare an argument to NaN in order to check if it's equal or the same. Confused? Let's walk through it.

Say, we need to check if a value is equal to 100 . That's easy, we can just compare it to itself like this:

const value = 100; value === 100; // true

Okay, let’s try this logic with NaN .

const value = NaN; value === NaN; // false

value == NaN; // false

☝️It doesn’t work 😫. NaN is a very special value that never equals to itself. And because of this problem. JavaScript created the global utility isNaN to help us check if a value is equal to NaN .

Problem with isNaN

As there is no easy way to check if a value is NaN because it doesn't equal to itself. The global utility isNaN was created to solve this dilemma.

const value = NaN; isNaN(value); // true ✅

This is great. But this utility has a problem 😑

const value = 'string'; isNaN(value); // true 😱

Do you see the problem? Let’s explain this in words. Does string equal to NaN ? Remember, don't think of NaN as "not a number", it's just a value called NaN. The answer is NO! string does not equal to NaN . Let me drill it down:

"string" === NaN; // false

"string" == NaN; // false

The Source of the isNaN Problem

Let’s go back to our definition of isNaN

Returns true if the argument coerces to NaN, and otherwise returns false.

See the word “coerce”. That’s the problem! It first coerces the value. In order words, it tries to convert the value into a Number type. Let’s see what happens when we do that.

const value = 'string'; Number(value); // NaN

☝️ Do you see it! When you try to convert the String type to a Number type, it returns NaN . And does the value NaN have the value of NaN ? The answer is yes. That's why it's returning true . BUT! That's not what we want. This is a false positive. In order to correct this, we don't want any coercion to occur!

Problem Solved with Number.isNaN

That’s why the Number.isNaN method was introduced! It solves the isNaN false positive problem. Number.isNaN doesn't do any coercion. In other words, it doesn't try to convert the argument's type to a Number type.

const value = 'string'; isNaN(value) // true ❌

Number.isNaN(value) // false ✅

Remember the question of the intention of these methods: “Does the value equal to NaN ". It is not asking if the value is "not a number". Sorry if I’m being repetitive. But this is the source of a lot of confusion from folks, so I really want to drill this concept down. Hopefully, everything is clear as mud now 🤞

Demo-ing Number.isNaN vs isNaN

This is pretty much the end of this post. But I just want to throw in some more examples to really bring the concept home 🥅

Example: Number

Does the value equal to NaN ? The answer is NO. So the result should be false . Remember it's not asking if the value is equal to "not a number".

const number = 100; isNaN(number) // false ✅

Number.isNaN(number) // false ✅

Example: NaN

Does the value equal to NaN ? The answer is YES. So the result should be true .

const nan = NaN; isNaN(number) // true ✅

Number.isNaN(number) // true ✅

Example: String

Always use Number.isNaN because the result from isNaN is incorrect. Remember the intention of the NaN-check, the method is asking: "Does the value equal to NaN ? It is NOT asking if the value is equal to "not a number".

So, in this example, does the String value equal to NaN ? The answer is NO. The result should be false .

const value = 'string'; isNaN(value) // true ❌

Number.isNaN(value) // false ✅

Conclusion