The article was originally posted on my personal blog.
I was recently answering an interesting question on Stack Overflow about the type of NaN
.
this is what´s happening
typeof Number.parseInt('processed')
prints 'number'
.
But if Number.parseInt('processed')
gives NaN
.
And indeed if you type in your browser console typeof NaN === 'number'
you'll get true. The comments to the answer made me realise that this is not another one of JavaScript quirks, but in fact a standard feature of all the programming languages that implement The IEEE Standard for Floating-Point Arithmetic (IEEE 754).
In Ruby, for example NaN
can be either an instance of Float
or BigDecimal
.
And indeed, if we look at the ECMA-262, 10th edition, the ECMAScript Language Specification, section 4.3.21 states that number type represents a "set of all possible Number values including the special “Not-a-Number” (NaN) value, positive infinity, and negative infinity". A few subsections below, section 4.3.24 clarifies that NaN is a "number value that is an IEEE 754-2008 “Not-a-Number” value".
So what is this IEEE 754 standard?
First published in 1985, its main purpose is to provide a computational method with floating point numbers, which would have the same results independent of the environment where the processing is done, be it software, hardware or a mix of both. Together with specifying formats and methods for floating-point arithmetic in computer programming environments, IEEE 754 also defines a set of special values: 0
(-0
and +0
are distinct values, although they both are equal; here's an in-depth article about both zero values in JS), denormalised number, positive and negative Infinity
, and NaN
, which the standard describes as a numeric data type that cannot be represented within the computing system. In fact, IEEE 754 defines two types of NaN
- a quiet NaN
(qNaN
) and a signalling NaN
(sNaN
). The most important difference between the two is that sNaN
will cause an exception when used in arithmetic operations and qNaN
won't. It seems like in JavaScript all the NaN
s are quiet, at least I wasn't able to find any information to the contrary.
Additionally, the standard defines an interesting list of special operations and their results:
number ÷ Infinity = 0
number ÷ -Infinity = -0
±Infinity × ±Infinity = ±Infinity
±non zero number ÷ ±0 = ±Infinity
number × ±Infinity = ±Infinity
Infinity + Infinity = ±Infinity
Infinity – -Infinity = +Infinity
-Infinity – Infinity = Infinity
-Infinity + – Infinity = Infinity
±0 ÷ ±0 = NaN
±Infinity ÷ ±Infinity = NaN
±Infinity × 0 = NaN
NaN == NaN (also '===' in JS) //False
Testing for NaN values
JavaScript doesn't have a single NaN
value, in fact, according to ECMA-262, there are "9007199254740990 (that is, 253 - 2) distinct “Not-a-Number” values of the IEEE Standard [...] represented in ECMAScript as a single special NaN value. In some implementations, external code might be able to detect a difference between various Not-a-Number values, but such behaviour is implementation-dependent; to ECMAScript code, all NaN values are indistinguishable from each other."
Because NaN
doesn't equal to itself (and in fact in some programming languages self-comparison is a widely used approach to test for NaN
s), we need to use a special Number.isNaN()
or isNaN()
methods to detect NaN
s. The difference between the two is that isNaN()
returns true
if the value is currently NaN
or it is going to be NaN after it's coerced to numeric value and Number.isNaN()
only will return true
if the value is currently NaN
. Generally Number.isNaN()
is more accurate since it also checks if the type of value is number. MDN has a handy explanation about testing against NaN.
Having "Not a Number" value to be a type of number is quite illogical, maybe a better name would be "Not a Real Number" or something along those lines. In this case, however, it's not a strange behaviour in JavaScript, but a general programming principle.
Got any questions/comments or other kinds of feedback about this post? Let me know here in the comments or on Twitter.
Top comments (6)
c/o "You Don't Know JS"
github.com/getify/You-Dont-Know-JS...
Despite the (condescending) name, the YDKJS series is actually really great.
did the interpreter work like this.
if (token[0] == 'NaN') return false;
return token[0] == token[1];
just kidding
Haha, well it's more like each NaN has a different value under the hood, so technically they're not equal to each other.
Fun fact: since most of the bits in NaN encoding aren't used to store any meaningful information, they can be manipulated to store actual data - payload. This is called NaN-tagging or NaN-boxing and is mostly used for adding additional type encodings to values. Here's one interesting article about it.
wow thank you, never thought about that
You are writing:
Following explanation helped me to accept fact that NaN is number type=):
Very interesting article. I never knew there was a difference between isNaN and Number.isNaN. Thanks for sharing!