DEV Community

Cover image for Does NaN actually means Not-a-Number?
Himanshu Ahuja
Himanshu Ahuja

Posted on • Updated on

Does NaN actually means Not-a-Number?

Consider we have the following mathematical operation to perform:

var a =  13 / "bar"; 

console.log(a); // NaN
Enter fullscreen mode Exit fullscreen mode

Any mathematical operation we perform without both operands being numbers, results in the operation failing to produce a valid number which we call as NaN.

From the above operation, a is NaN and if we do:

console.log(typeof a === "number") // true
Enter fullscreen mode Exit fullscreen mode

Surprised??

If NaN means not-a-number, then why typeof NaN is number?

Confusing isn't it?

Let's talk more about What exactly does NaN means?

It isn't quite accurate to think of NaN as "not a number". Rather, it is more accurate to think of it as being an "invalid number", "failed number", or even "bad number".

NaN is a kind of "sentinel value" that represents a special kind of error condition within the number set. We can think of it like: "Hey, I tried to perform a mathematic operation but failed, so here's the failed number result instead".

Now if we have some value in a variable and we want to test and see if it's this special failed number NaN, how will we do it?

One thing which will first come in our mind is to use the comparison operators and using those, we can compare the variable with the NaN itself.

Simple isn't it? Let see....

var a =  13 / "bar";

console.log(a == NaN) // false
console.log(a === NaN) // false
Enter fullscreen mode Exit fullscreen mode

More confusion isn't it? Lets understand a bit more about NaN.

NaN is a very special value in that it's never equal to another NaN value.(i.e. it's never equal to itself).

So even if we do below:

console.log(a == a) // false
console.log(a === a) // false
Enter fullscreen mode Exit fullscreen mode

The results in both cases is going to be false. NaN is the only value in the whole language where NaN isn't equal to itself.

Now the question arises, how do we test for it if we can't compare NaN?

For this, we use a built-in global utility function called isNaN(...).

var a =  13 / "bar";

console.log(isNaN(a)) // true
Enter fullscreen mode Exit fullscreen mode

Simple enough right?

Actually, this isNaN(...) has a fatal flaw. It appears that it takes meaning of NaN as Not-a-Number too literally.

See the below example:

var a =  13 / "bar";
var b = "foo";

console.log(isNaN(a)) // true
console.log(isNaN(b)) // true
Enter fullscreen mode Exit fullscreen mode

From the example above, it is just checking "if the thing passed in is either a number or not a number".

Clearly, "foo" is literally not a number, but it's definitely not the NaN value either. This is the bug in JS since very beginning.

As of ES6, finally a replacement utility has been provided: Number.isNaN(...) which solves the above problem.

Simple Polyfill for this for checking the NaN values in pre-ES6 browsers is:

if (!Number.isNaN) {
    Number.isNaN = function(n) {
        return(
            typeof n === 'number' && isNaN(n)
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

We can implement this Polyfill in an easy way by taking advantage of the fact that NaN isn't equal to itself.

if (!Number.isNaN) {
    Number.isNaN = function(n) {
        return n !== n;
    }
}
Enter fullscreen mode Exit fullscreen mode

If you're currently using just isNaN(...) in a program, the sad reality is your program has a bug, even if you haven't been bitten by it yet. So now is the really good idea to use reliable test, like Number.isNaN(...) as provided.

That is all for the topic. Hope you like it.

Reference: You Don't know JS by Kyle Simpson

Top comments (6)

Collapse
 
ashcript profile image
As Manjaka Josvah • Edited

I think the function isNaN implicitly coerces the value inside it into number first. I mean :

isNaN(a) 
// Equivalents to :
isNaN(Number(a));
Enter fullscreen mode Exit fullscreen mode

If it can't coerce that value into a valid number, then it returns true. Example :

var a = '123';
var b = 'foo';
var c = true;

console.log(isNaN(a)); // equivalents to isNaN(Number(a));
// Returns false because **Number(a) = 123** is a valid number.

console.log(isNaN(b)); // equivalents to isNaN(Number(b));
// Returns true because **b** is an invalid number, and **Number(b) returns NaN**

console.log(isNaN(c)); // equivalents to isNaN(Number(c));
// Returns false because **Number(c) = 1** is a valid number.

Enter fullscreen mode Exit fullscreen mode
Collapse
 
ashcript profile image
As Manjaka Josvah

How about null == undefined which returns true? We know that Number(undefined) is NaN, and Number(null) is 0, but 0 == NaN returns false. So peculiar πŸ˜΅β€πŸ’«

Collapse
 
dragosdev profile image
Dragos Barbuta

It is not peculiar at all if you read the specs of javascript and understand how double equals work under the hood: here

If x is null and y is undefined, or vice versa, the method returns true because null and undefined are considered loosely equal.

Collapse
 
ashcript profile image
As Manjaka Josvah • Edited

I'm on my way to learn it deeply bro, but thanks. But why could we say they are loose equal? I've tried all the possible explicit coercion between null and undefined, but the only point they're same is when we use the Boolean object wrapper form as : Boolean(null) and Boolean(undefined). Behind the loose equal, there is always coercion, and I'm learning about it right now.


Maybe because null == void 0 is true and undefined == void 0 is true too πŸ₯΄, so that's why they are loose equal πŸ₯΄.

void 0 == null // true
void 0 == undefined // true
// So :
null == undefined // true
// But :
null == 0 // false 🀣
Enter fullscreen mode Exit fullscreen mode



If I can't get it on my own, I'll read this spec as you suggested me.

Thread Thread
 
dragosdev profile image
Dragos Barbuta

No worries, javascript can really be tricky sometimes, it's good that you're trying to learn more about it :)

When we talk about "loose" equality in JavaScript, we're referring to the == operator, which allows for type coercion. This is different from "strict" equality (===), which does not.

The JavaScript spec indeed states that null and undefined are considered loosely equal, which is why null == undefined returns true. This is a special rule, separate from the normal rules of type coercion.

When you do null == 0, it returns false because null and 0 aren't the same type, and there's no rule that allows null to be coerced into 0. However, null and undefined have that special exception in the specification, hence they are loosely equal.

void 0 is another way to produce undefined, so null == void 0 is also true due to the special rule.

So the behavior isn't really about what values null and undefined coerce to in various contexts, but rather about the specific rules for == in the JavaScript spec.

I hope that it was clear :D

Collapse
 
karim_abdallah profile image
Karim Abdallah

awesome