NaN or Not a Number?

Day 9 of National Blog Posting Month #NaBloPoMo

Following yesterday’s post on handling null, undefined and zero values in JS, I was asked on Mastodon:

I’m curious why isNaN() doesn’t work in your case. Thanks!

isNan() is a global function, which determines if a value evaluates to NaN or not. But what is NaN?

NaN

NaN (not to be confused with your grandma) in JavaScript stands for Not A Number. It’s relatively common for NaN to appear in JS code as a result of an impossible math operation, which can occur when passing a value of the wrong type into a function. For example:

console.log(1 / undefined) // NaN
console.log(1 / 'abc') // NaN

NaN is a mathematical expression (rather than something that comes from JavaScript), and so, confusingly can also be thought of as a number! We can see that it is actually a type of number:

const value = 1 / 'abc'

console.log(value) // NaN
console.log(typeof value) // 'number'

isNaN()

We can use isNaN() to test whether a value evaluates to NaN. But it can be surprising. '1', 'abc', '' (an empty string), null and '002' are all clearly not numbers. But if we pass them into isNaN(), only two of them evaluate true:

console.log(isNaN('1')) // false
console.log(isNaN('')) // false
console.log(isNaN('abc')) // true
console.log(isNaN(null)) // false
console.log(isNaN(undefined)) // true
console.log(isNaN('002')) // false

isNan() attempts first to convert the value to a number. null or an empty string are coerced to 0, for instance, meaning they can be parsed as numbers. Of these examples, only 'abc' and undefined cannot be parsed as a numbers.

On the other hand, we can use the more robust Number.isNaN(), which does not first attempt to convert the value to a number:

console.log(Number.isNaN('1')) // false
console.log(Number.isNaN('')) // false
console.log(Number.isNaN('abc')) // false
console.log(Number.isNaN(null)) // false
console.log(Number.isNaN(undefined)) // false
console.log(Number.isNaN('002')) // false

In this case, all of the expressions evaluate false.

Filtering data

Going back to yesterday’s example of filtering an array to remove null or undefined values, we can see that isNaN() (or Number.isNaN()) won’t cut it.

const data = [100, 52, null, 12, 71, '', undefined]

data.filter((value) => !isNaN(value))
// Results in [100, 52, null, 12, 71, '']
data.filter((value) => !Number.isNaN(value))
// Results in [100, 52, null, 12, 71, '', undefined]

These filter functions don’t determine whether a value is a number, only whether a value is not Not A Number (NaN)! Therefore non-number values won’t all be filtered out.

To truly ensure that our filtered data only includes numbers, we can check if the type of each value is 'number':

data.filter((value) => typeof value === 'number')

However, as we’ve seen above, NaN is a type of number! So NaN values won’t be filtered out here.

const value = 1 / 'abc'
const data = [100, 52, null, 12, 71, '', undefined, value]

data.filter((value) => typeof value === 'number')
// Results in: [100, 52, 12, 71, NaN]

To make our function even more robust, let’s use isNaN() to cover those too:

data.filter((value) => {
  return typeof value === 'number' && !isNaN(value)
})
// Results in: [100, 52, 12, 71] ☺️

Webmentions for this page

About webmentions

Likes: 0

Reposts: 0

Mentions: 1