NaN and typeof

An in-depth look at the NaN property, and why it is considered a number type

We all love JavaScript

First, NaN is not a keyword (unlike true, false, null, etc..), it is a property of the global object. The value of NaN is the same as the value of Number.NaN:

NaN; // NaN

Number.NaN; // NaN

There are several ways in which NaN can happen:

Division of zero by zero Dividing an infinity by an infinity Multiplication of an infinity by a zero Any operation in which NaN is an operand Converting a non-numeric string or undefined into a number

Why does typeof NaN return “number”?

typeof NaN; // "number"

The ECMAScript standard states that Numbers should be IEEE-754 floating point data. This includes Infinity, -Infinity, and also NaN.

By definition, NaN is the return value from operations which have an undefined numerical result. Hence why, in JavaScript, aside from being part of the global object, it is also part of the Number object: Number.NaN. It is still a numeric data type, but it is undefined as a real number.

NaN also represents any number outside of the ECMAScript domain of definition.

Computer arithmetic is limited

Consider the following operation:

(3.2317006071311 * 10e616) / (3.2317006071311 * 10e616); // NaN

As Wikipedia states:

Computer arithmetic cannot directly operate on real numbers, but only on a finite subset of rational numbers, limited by the number of bits used to store them.

In ordinary arithmetic, 3.2317006071311 * 10616 is a real finite number, but, by ECMAScript standards, it is simply too large (i.e, considerably greater than Number.MAX_VALUE), and is therefore represented as Infinity. Attempting to divide an infinity by an infinity yields NaN. Of course, in ordinary arithmetic, since both operands are finite, the operation clearly equals 1.

In this case, the NaN is in place of a real number that it could not compute (i.e, 1) due to the size of the operands. It would seem counter-intuitive if typeof NaN were to return something other than ”number”. After all, in this example, NaN simply represents a value which could not be determined by computer arithmetic.

(Note: the value 3.2317006071311 * 10616 was computed by taking Number.MAX_VALUE and squaring it manually, in ordinary arithmetic)

NaN is unordered

According to the IEEE 754 floating-point standard, comparison with NaN always returns an unordered result. That is, NaN is not equal to, greater than, or less than anything, including itself:

NaN < 1; // false

NaN > 1; // false

NaN == NaN; // false

// But we can still check for NaN:

isNaN(NaN); // true

This is why you cannot determine whether a given value is NaN by comparing it to NaN, and instead you must use the isNaN() function.

It is not surprising, then, that the native implementation of the function isNaN() could be simply replaced with:

// Native implementation

function isNaN(x) {

// Coerce into number

x = Number(x);

// if x is NaN, NaN != NaN is true, otherwise it's false

return x != x;

}

The native implementation of isNaN() returns true even if the value is undefined, or if the value cannot be coerced into a primitive number data type.

Of course, I wouldn’t recommend replacing the native implementation. However, there are some libraries out there which introduce their own. For example, Underscore’s implementation is as follows:

_.isNaN = function(obj) {

// `NaN` is the only value for which `===` is not reflexive.

return obj !== obj;

};

But, its behavior is not same as the native isNaN() function:

var x; // undefined

isNaN(x); // true

isNaN(undefined); // true

isNaN("a"); // true

compared to Underscore’s:

var x; // undefined

_.isNaN(x); // false

_.isNaN(undefined); // false

_.isNaN("a"); // false

I can’t be certain, but I suppose Underscore included this implementation because you might be interested in checking that the value is indeed NaN, since the only value that satisfies an inequality check against itself is NaN.

Booleans are not NaNs

Consider the following code:

isNaN(true); // false

isNaN(false); // false

This is because booleans are considered and implemented as numerical values with a single binary digit (i.e., bit), thus they are coerced into their respective bit representations: