Everything you need to know about NaN in JavaScript
Tags: javascript, node
Published: 2020-02-28 16:31:54

`NaN` is a global property that represents the value of Not-A-Number, hence the name. It is possible to get the value `NaN` returned when doing an arithmetic operation or coercing some value to a number. Here are some operations that result in `NaN`

```javascript
0 / 0; // NaN
Infinity / Infinity; // NaN
1 / undefined; // NaN
undefined / 1; // NaN

// [almost] all arithmetic operation involving NaN

NaN + 1; // NaN
NaN - 1; // NaN
NaN * 1; // NaN
NaN / 1; // NaN
NaN ** 1; // NaN
NaN % 1; // NaN
// with the exception of
NaN ** 0; // 1

// Finally, coercing any value that does not have a numeric value

parseInt('hi', 10); // NaN
parseFloat(undefined); // NaN
+"hi"; // NaN
Number({}); // NaN
"hi" - 1; // NaN
"hi" * 1; // NaN
"hi" / 1; // NaN
"hi" % 1; // NaN
"hi" ** 1; // NaN
```

it is worth mentioning that most of the confusion about `NaN` comes from the behavior of coercing a non-numeric-value to a numeric-value which results in `NaN`. For this reason, I recommend getting yourself familiarized with the last few examples from the code above and better yet why some values such as booleans, `[1]` and `''` do not result in `NaN`

### Interesting facts about  `NaN`

`NaN` has a bad reputation for being tricky, however, if you familiarize yourself with the following few facts you will be able to work with `NaN` with no issue.

`NaN` unlike it's name is actually from the type Number

```javascript
typeof NaN; // 'number'
```

`NaN` Has a falsy value

```javascript
Boolean(NaN); // false
```

`NaN` is the only value in JavaScript that does not equal itself. Hint: this will become useful later on.

```javascript
NaN === NaN; // false
NaN == NaN; // false
NaN !== NaN; // true

// No, it is not pointing to a differnt NaN object (no such thing)
const iAmNaN = NaN;
iAmNaN == iAmNaN; //false
```

You can access `NaN` in four different ways.

```javascript
NaN;
this.NaN;
globalThis.NaN;
Number.NaN
```

Avoid comparisons with `NaN`

```javascript
NaN > 0; // false
NaN >= 0; // false
NaN < 0; // false
```

### Let's look at an example

Let's say we have a function that takes one argument and increments it by `10` .  We want to accept both numbers and strings representing a number so we will use `parseFloat`

```javascript
const incrementByTen = function(val) {
  const n = parseFloat(val, 10);
  return n + 10;
};

incrementByTen(0); // 10 ✅
incrementByTen('2.3'); // 12.3 ✅

/*
  result of parseFloat will be NaN in examples below
  hence the addition operations will also return NaN
*/
incrementByTen(NaN); // NaN ❌
incrementByTen(false); // NaN ❌
incrementByTen({}); // NaN ❌
incrementByTen([]); // NaN ❌
incrementByTen('a'); // NaN ❌
incrementByTen(true); // NaN ❌
incrementByTen(['a', 1]); // NaN ❌
```

We just learned there are plenty of arguments which would result in `NaN`. Perhaps a better way to handle this is to throw an error for those cases. However, as we learned earlier the usual comparisons will not work for `NaN` as we can see below. For this reason, we will use the global function `isNaN`.

```javascript
typeof NaN === NaN; // false
NaN === NaN; // false
```

## what is `isNaN` and how it works?

`isNaN` is a global function, takes a single argument and returns a boolean indicating whether or not the argument passed is `NaN`. MDN explains `isNaN` as such:

> The function [ `isNaN` ] should be interpreted as answering the question, "is this value, when coerced to a numeric value, an IEEE-754 'Not A Number' value?"

We now write our function with `isNaN` to throw an error when the result of the `parseFloat`  is `NaN`.

```javascript
const incrementByTen = function(val) {
  const n = parseFloat(val, 10);
  if (isNaN(n)) {
    throw new Error('Resulted in NaN!');
  }
  return n + 10;
};

incrementByTen(0); // 10 ✅
incrementByTen('2.3'); // 12.3 ✅
incrementByTen(NaN); // Error: Resulted in NaN! ✅
incrementByTen(false); // Error: Resulted in NaN! ✅
incrementByTen({}); // Error: Resulted in NaN! ✅
incrementByTen([]); // Error: Resulted in NaN! ✅
incrementByTen('a'); // Error: Resulted in NaN! ✅
incrementByTen(true); // Error: Resulted in NaN! ✅
incrementByTen(['a', 1]); // Error: Resulted in NaN! ✅
```

Great, our function works as expected. Now let's learn a bit more about `isNaN`. Best way to understand how `isNaN` works is to create our own [basic version] polyfill for it. Polyfill is not required to use `isNaN`, It is super old...IE 3 old! 👴🏽

```javascript
const isNaN = function(value) {
  // coercing it into a numeric value. BEWARE OF THIS LINE
  const n = Number(value);
  // now checking to see if it does not equal itself
  // only NaN does not equal itself 🤯
  return n !== n;
};
```

When working with `isNaN` you need to beware of the coercion of the value to a numeric-value.  Remember some values cannot be coerced to a numeric-value and will result in `NaN` so even though your argument to `isNaN` might not have been `NaN` it could become one.

Here are a few examples where this happens and `isNaN` does not work as we perhaps expect it to:

```javascript
isNaN(NaN); // true ✅

isNaN(undefined); // true ❌
isNaN('a'); // true ❌
isNaN({}); // true ❌
isNaN(['a']); // true ❌
isNaN(10n); // TypeError: Cannot convert a BigInt value to a number ❌
isNaN(Symbol()); // Uncaught TypeError: Cannot convert a Symbol value to a number ❌
```

## `Number.isNaN` to the rescue 🦸🏻‍♀️

For the reasons that should be clear from above using `isNaN` is not ideal. This is why `Number.isNaN` has been added to JavaScript starting from ES6. The main difference between the two functions is that `Number.isNaN` does not convert its argument to a numeric-value before determining whether it is `NaN`.

```javascript
Number.isNaN(NaN); // true ✅

Number.isNaN(undefined); // false ✅
Number.isNaN('a'); // false ✅
Number.isNaN({}); // false ✅
Number.isNaN(['a']); // false ✅
Number.isNaN(10n); // false ✅
Number.isNaN(Symbol()); // false ✅
```

Great, it is working as expected. I recommend to always use `Number.isNaN`. Even if you want to coerce the value to a numeric-value do it yourself and then use `Number.isNaN` that way you are clearly expressing your intentions.

```javascript
// Bad
isNaN(someValue);

// Good
Number.isNaN(someValue)

// And if we do need someValue to be coerced to a numeric-value
const numericalValue = +someValue; // or Number(someValue)
Number.isNaN(numericalValue);
```

# Alternatives to native `isNaN` and `Number.isNaN`

As you can imagine before `Number.isNaN` was introduced there were some workarounds for us to handle this which perhaps are no longer needed but worth noting.

### Write your own

If you are not going to use `Number.isNaN`, this is perhaps the quickest and fastest way to get going. The key to understanding this function is that `isNaN` is the only value that does not equal itself.

```javascript
const _isNaN = function(value) {
  return value !== value;
}
```

### Lodash and Underscore

Both of these popular utility libraries have their own version of the functionality which works similar to `Number.isNaN`

```javascript
import lodash from 'lodash';
import underscore from 'underscore';

lodash.isNaN();
underscore.isNaN();
```

## Resources and citations

- `NaN`
    - MDN [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN)
    - ECMAScript Spec [https://tc39.es/ecma262/#sec-value-properties-of-the-global-object-nan](https://tc39.es/ecma262/#sec-value-properties-of-the-global-object-nan)
- `isNaN`
    - MDN: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN)
    - ECMAScript Spec [https://tc39.es/ecma262/#sec-isnan-number](https://tc39.es/ecma262/#sec-isnan-number)
    - Lodash [https://lodash.com/docs/4.17.15#isNaN](https://lodash.com/docs/4.17.15#isNaN)
    - Underscore [https://underscorejs.org/#isNaN](https://underscorejs.org/#isNaN)
- `Number.isNaN`
    - MDN [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN)
    - ECMAScript Spec [https://tc39.es/ecma262/#sec-number.isnan](https://tc39.es/ecma262/#sec-number.isnan)
- Related topics
    - freeCodeCamp: JavaScript type coercion explained  [https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/](https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/)
    - SitePoint ES6 New Number Methods [https://www.sitepoint.com/es6-number-methods/](https://www.sitepoint.com/es6-number-methods/)