I was on a video streaming site recently and moved the play point to the far right. It was amusing to see the hover details show *NaN:NaN* – ahah, some mathematical operation had *NaN-ed* and the code didn’t cater for that.

If you have read Why JavaScript ‘seems’ to get addition wrong; you would have seen that some operations do result in a *NaN*. *NaN* is a value with its roots in the IEEE754 standard definition.

**What is NaN?**

Nan literally means *Not a Number.* Yes, it means that value is not a number and occurs when you try to coerce a non-mathematical value (e.g. string) into a number.

**How do you check if a value is NaN**

How do you know if some value is *NaN*? Turns out this is not so straightforward.

For numbers, we typically compare to the expected value and that is usually *true; *however the case for *NaN* is different.

let two = 2; two === 2; // true two == 2; // true // NaN let x = NaN; x === NaN; // false x == NaN; // false x === x; // false ???

**Unequal ‘equalities’ in Maths and JavaScript**

You might be scratching your head and wondering if there are other values that can be unequal. Yes, there is one – Infinity. In Mathematics, infinite values are not equal even if most operations assume this for simplicity.

Imagine two containers of water – a large jug and a small cup. Both contain infinite amounts of atoms right? Yet, it is obvious that the infinite amount of atoms in the large jug is **greater** than the infinite amount of atoms present in the small cup. The inability to determine a specific value doesn’t automatically make all infinite values equal.

Thus, even though the result of 1 * ∞ and 10 * ∞ are both ∞ in most languages; we can argue the latter is a ‘larger’ type of ∞. It might not matter so much given that computers have finite storage limits. For a more in-depth discussion of this, read Jeremy Kun’s excellent post.

Let’s see if JavaScript obeys this Maths law.

let infinity = Infinity; infinity === Infinity; // true (2 * Infinity) === (10 * Infinity); // true

So JavaScript coalesces all Infinity values and makes them ‘equal’. But *NaN* is exempt from this as shown earlier.

The good thing is that this special quality of *NaN* stands out. According to the IEEE754 standard, *NaN *cannot be *equal* to anything (even itself). Thus to determine if a value is *NaN,* you can check if that value is not equal to itself.

let nan = NaN; nan === nan; // false nan !== nan; // true

**The Issue with JavaScript’s isNaN**

JavaScript exposes the *isNaN *method for checking for *NaN* values. The snag however is that it behaves unreliably with varying operand types.

isNaN(NaN); // true isNaN(2); // false isNaN('a'); // true isNaN(); // true isNaN(null); // false isNaN(true); // false

Surprised? Again, this is the exhibition of one of JavaScript’s quirks. The spec reads thus:

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

And what’s the *toNumber *coercion table?

Value | Numeric value |
---|---|

null | 0 |

undefined | NaN |

true | 1 |

false | 0 |

123 | 123 |

[] | 0 |

{} | NaN |

So you now know why *isNaN() *and *isNaN({a: 1}) *are both *true *even though *isNaN([]) *is false. Even though arrays are objects, their *toNumber* coercion is not *NaN (*as shown in the table above). Similarly since the boolean primitives coerce to numbers; calling *isNaN(true) *or *isNaN(false)* will give a *false *outcome.

**Reliably verifying NaN values**

There are two fixes to this

1. Prior to ES6, the only way is to check if the value is not equal to itself.

function isReliablyNaN(x) { return x !== x; }

2. ES6 introduces the *Number.isNaN* method which avoids the inherent *toNumber *coercion of *isNaN***. **This ensures that only *NaN* returns true.

Number.isNaN(NaN); // true // All work as expected now Number.isNaN(2); // false Number. isNaN('a'); // false Number. isNaN(); // false Number. isNaN(null); // false Number.isNaN(true); // false

**Conclusion**

If you are using *isNaN* in your code; you most likely have a bug waiting to happen some day some time.

You should switch to *Number.isNaN *which is already supported by all major browsers except IE11 and also add a polyfill fallback (just in case). You should also know that *isFinite* uses *isNaN *internally and consequently suffers the same flaws. Use *Number.isFinite* instead.

I would have wanted a reliable *isNaN *implementation but alas the special characteristic has now become a ‘feature’ and can’t even be fixed for backwards compatibility reasons.

**Related**

If you enjoyed this post and wanted to learn more; here are a couple of posts explaining various quirky behaviours in JavaScript.

Leave a Reply