DEV Community

Amr Mohamed
Amr Mohamed

Posted on • Updated on

Why NaN === NaN returns false in JavaScript ?!

When people start exploring topics about JavaScript they get to feel a little weird sometimes and they also start to wonder why the heck do JavaScript act in such a manner, there have been even Github Repos like You Don't Know JS that explains how JavaScript works and so.

Today I wanted to explain a gotcha topic that people usually post memes about and hate on JavaScript because of such a topic ( Which I kinda understand why they do so ), I will be explaining why NaN === NaN results in a Falsy expression. Let us get started with some basics first.

What is the difference between == and ===

Whenever we compare two variables using the double equal operator we compare them using only their values, meaning if a variable A contains some value and variable B contains some other value and we did A == B what will happen is that JavaScript will check their current values and return true if they are equal.

but what if we did something like this: "1" == 1, what would be the result of such expression?

A normal person with some logical understanding would definitely guess that the output would be false because we are comparing a string to a number even if they have the same characters.

What will actually happen is that this output will be expressed as true. Why is that? When we use the double equal operator JavaScript will attempt to convert and compare operands of different types, meaning that they both would be converted to the same type and in case of comparing a number to a string JavaScript will try and convert the string to a number type like this: Number("1") == 1 which will output in that case true.

What if we have a case in which we actually want to compare the types of the variables we have and then compare their values without attempting any conversion?
In that case, using the triple equal operators or the Strict equality would come in handy, what the strict equality operator simply does is checking if the operands are of the same type and then checks if they have the same value or not.

let a = "1";
let b = 1;

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

We could simply imagine that JavaScript under the hood does something like this when using the strict equality:

let a = "1";
let b = 1;

console.log(typeof a == typeof b && a == b)  // in case of doing a === b;
Enter fullscreen mode Exit fullscreen mode

What is NaN

According to the MDN documentation NaN is:

NaN is a property of the global object. In other words, it is a variable in global scope.

So basically NaN is simply a global object that describes what a not number is or whenever we have a variable that we are attempting to convert to a number and we fail it simply gives us NaN like this:

let a = "hello world";
let convertedToNumber = Number(a);

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

What is typeof

typeof is simply a JavaScript operator that returns a string that indicates the type of an operand.

There are basically 9 types in JavaScript:

  • Undefined "undefined"
  • Null "object" (see below)
  • Boolean "boolean"
  • Number "number"
  • BigInt "bigint"
  • String "string"
  • Symbol "symbol"
  • Function object (implements [[Call]] in ECMA-262 terms) "function"
  • object "object"

Whenever typeof is used one of these types would be the result, an example for that would be:

typeof "" // string;
typeof 1 // number;
typeof function() {} // function;
typeof true // boolean;
Enter fullscreen mode Exit fullscreen mode

Why NaN === NaN returns false?

And finally, let us get into the core of this article, why when we explained how strict equality works and what is NaN does this expression provide us with a falsy value?

let us simplify the answer by looking into the strict equality comparison algorithm:

let us define the following two operands: x, and y.

according to the JavaScript documentation ( This is a snippet from the docs ), the comparison algorithm works in the following matter:

The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:

If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.

This means that the algorithm first checks if one of the operands is NaN before even checking their types and if so it will return false anyways.

This may be a weird implementation of the comparison algorithm but there are some workarounds for this, we could use built-in functions like Number.isNaN() to check whether the giving parameter is a NaN or not instead of comparing it with NaN directly

let invalidNumber = Number("asdasdasd"); // NaN;

let resultOfNormalComparison = invalidNumber === NaN; // false;
let resultOfBuiltInComparison = Number.isNaN(invalidNumber); // true;
Enter fullscreen mode Exit fullscreen mode

Edit:
This part is being edited after recieving comments about why actually NaN is not equal to NaN from a mathematical prespective, I came accross this answer in stackoverflow and it helped me alot, would recommend it to anyone: answer

Conclusion

You could somehow disagree on the implementation of the comparison algorithm but there are workarounds to check if a given variable or parameter is a NaN or not as shown above.

References:

Top comments (5)

Collapse
 
lexlohr profile image
Alex Lohr

This explains what NaN is, but not the reason why Brendan Eich came up with it, which is: in algebraic functions, there may be undefined results, for example Math.sqrt(-1). If one would be handling these results as undefined, they would be coerced to zero in further operations, which could lead to results that are mistaken for correct ones. Thus every mathematical operation with NaN yields NaN and comparisons always fail.

Collapse
 
jessekphillips profile image
Jesse Phillips • Edited

It is because the floating point standard requires it en.m.wikipedia.org/wiki/IEEE_754

And as Alex Lohr points out this is very important in mathematics because

var a = 6 + 9;
var b = average() - 3;

if(a  < b)...
Enter fullscreen mode Exit fullscreen mode

If average() is NAN, b is NAN, the condition is false. Now that does not mean an else clause can assume a >= b because that is also false. But this ensures we don't try average() == mean() and go down a path where clearly we don't know.

Collapse
 
jcubic profile image
Jakub T. Jankiewicz

Note that you didn't actually explained why NaN === NaN return false. You only explained that this is how it works. But the reason is because of IEEE 754 floating-point standard that specified how NaN should behave en.wikipedia.org/wiki/NaN

Collapse
 
amrtaher1234 profile image
Amr Mohamed

Yep, I added a reference explaining it further more

Collapse
 
amrtaher1234 profile image
Amr Mohamed

That is correct, thanks for the addition!