Not-A-Number, or just NaN, is a property of JavaScript’s global object. It is a non-configurable, non-writeable property meaning that it is best we don’t try and mess with it too much, and the reason this blog entry exists if because I made the mistake of trying to outwit JavaScript.

Context

I was working on a rather simple program that would console log a message depending on the hour. The function would take a string as an argument in the format of “HH:MM”, 24-hour clock. My initial idea was to slice that string in order to take the first two characters, turn them into a Number and apply conditionals to return a message depending on the hour.

function greet(time) {
  let hour = Number(time.slice(0, 2));
  if (hour < 12 {
    return 'Good Morning';
  } else if (hour < 17) {
    return 'Good Afternoon';
  } else {
    return 'Good Evening';
  }
}

Pretty simple huh? So I thought…

At this point, I was getting the following return values:

greet('8:40'); // 'Good Evening'
greet('14:21'); // 'Good Afternoon'
greet('19:00'); // 'Good Evening'

Hol’ up. Something doesn’t seem right.

It just so happens that if the string passed into the greet function was a single digit hour, it would include the colon that separates the hours from minutes. Then try to convert '8:' to a Number, resulting in NaN.

How I Tried to Outwit JavaScript and Miserably Failed

Well, this one is an easy fix… just gotta compare hour to NaN and enter the first condition/get the first return value, because hour will only be NaN if it’s a morning hour… right?

function greet(time) {
  let hour = Number(time.slice(0, 2));
  if (hour < 12 || hour === NaN {
    return 'Good Morning';
  } else if (hour < 17) {
    return 'Good Afternoon';
  } else {
    return 'Good Evening';
  }
}

it makes sense, but the output values of this were the same as the ones previously. Why? turns out NaN === NaN returns false.

obama-wut

But NaN IS NaN, what do you mean?!?!?!!?

Yeah, thought so too. The proper way to check if something is NaN is by using JavaScript’s global function isNaN().

Testing Against NaN

From Mozilla’s Developer Network (MDN) site:

NaN === NaN;        // false
Number.NaN === NaN; // false
isNaN(NaN);         // true
isNaN(Number.NaN);  // true

Solution

Now that we know what to expect from NaN, we can update the greet function:

function greet(time) {
  let hour = Number(time.slice(0, 2));
  
  if (hour < 12 || isNaN(hour)) {
    return 'Good Morning';
  } else if (hour < 17) {
    return 'Good Afternoon';
  } else {
    return 'Good Evening';
  }
}

greet('8:40'); // 'Good Morning'
greet('14:21'); // 'Good Afternoon'
greet('19:00'); // 'Good Evening'

Awesome! But in the future I’ll probably avoid using NaN to compare values and save myself the trouble.

Understanding NaN usage in Strict Equality Comparison

Straight from JS’s documentation:

7.2.16 Strict Equality Comparison

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 different from Type(y), return false.

If Type(x) is Number or BigInt, then

Return ! Type(x)::equal(x, y).

Return ! SameValueNonNumeric(x, y).

NOTE

This algorithm differs from the SameValue Algorithm in its treatment of signed zeroes and NaNs.

So basically NaN === NaN returns false because the spec says so.

It follows the Institute of Electrical and Electronics Engineers specification: Standard for Floating-Point Arithmetic (IEEE 754). This standarizes the behaviour of NaN values, and IEEE 754 specifies that NaNs are never equal.

And, from the MDN website this only happens with NaN values:

NaN, and only NaN, will compare unequal to itself

Conclusion

NaN values are complicated to work with, most times it is better to just avoid using it as part of your function. If you must use it, the JS spec and MDN are pretty straightforward and useful resources.

Useful Resources:

ECMAScript 2020 Standard: Strict Equality Comparison

MDN – Global Objects

MDN – Global Objects: NaN

IEEE 754

Why is NaN === NaN false? (Stack Overflow)

NaN and typeof