Why does isNaN(null) return "false"?

Asked

Viewed 194 times

6

I came across a situation where undefined and null return a different value to the function isNaN, while I hoped they would both return true (are not numbers).

In the example below I also put a string abc and a number 123 for the function isNaN, that return me the expected value.

console.log('isNaN(undefined):', isNaN(undefined)); // true
console.log('isNaN(null):', isNaN(null)); // false
console.log('isNaN("abc"):', isNaN("abc")); // true
console.log('isNaN(123):', isNaN(123)); // false

  • Why null is being considered a number and undefined nay?
  • This is the expected behavior or may vary according to the environment (browser, Node.js, Deno etc.)?

3 answers

10


Why isNaN(null) returns false?

Because null can be converted to a numerical representation in Javascript. In this case, null is "equivalent" to the 0 after coercion.

The difference can be noticed from this example:

console.log(Number(null), isNaN(null)); // 0 false
console.log(Number(undefined), isNaN(undefined)); // NaN true

Javascript is a language that eventually makes automatic type coercion. The constructor Number allows us to make this coercion to the type number explicitly. Checking this behavior, it is noted that null is convertible the numerical type (resulting in 0), while undefined no (resulting in NaN).

The function (present in the global scope) isNaN checks whether the argument can be correctly converted to a numerical representation. If conversion is possible, it is returned true and otherwise not. That’s why isNaN(null) returns false and isNaN(undefined) returns true.


It is worth remembering that isNaN (of the overall scope) is different of the static method Number.isNaN. The nomenclature is confusing and, following the name, both had to do the same thing, but:

  • isNaN checks whether the argument can be converted correctly to a numerical representation (without returning NaN). Check the algorithm specified for the isNaN.
  • Number.isNaN checks (using a different but similar algorithm to ===) whether the argument given is equal to NaN. See the specification his as well.

The isNaN works with a larger set of values. Antagonistically, the Number.isNaN will return true only when the past value is literally equal to NaN. Otherwise, you will always return false.

Some examples to verify the difference:

console.log(isNaN(5), Number.isNaN(5)); // false false
console.log(isNaN(NaN), Number.isNaN(NaN)); // true true
console.log(isNaN(null), Number.isNaN(null)); // false false
console.log(isNaN(undefined), Number.isNaN(undefined)); // true false

This is the expected behavior or may vary according to the environment (browser, Node.js, Deno etc.)?

The behavior of both functions is standardized by the specification. Therefore, it is expected to work in all browsers and runtimes.

The only caveat is that Number.isNaN was introduced in Ecmascript 2015 (ES6).

4

The question has already been answered, but I would like to add some information here.

The behavior of isNaN

The behavior mentioned in the question is in accordance with the specifications of Ecmascript, since isNaN carry out the verification through the specifications of ToNumber - if ToNumber returns NaN or not:

Returns true if the argument coerces to Nan, and otherwise Returns false.

  1. If Tonumber(number) is Nan, Return true.
  2. Otherwise, Return false.

Knowing that isNaN in fact seeks the numerical representation of the given value, only remains to know, by definition of Ecmascript, what ToNumber(null) and ToNumber(undefined) should return.

The conversion to number (ToNumber)

ToNumber is an abstract operation that follows the following algorithm (in free translation):

Script Type Upshot
Undefined Returns NaN.
Null Returns +0.
Boolean If the argument is true, returns 1. If the argument is false, returns +0.
Number Returns the argument (no conversion).
String See the algorithm here.
Symbol Makes an exception TypeError.
Bigint Makes an exception TypeError.
Object Apply the following steps:
1. Convert to primitive with ToPrimitive.
2. Return ToNumber(valorPrimitivo).

So that already tells us that isNaN(undefined) === true and isNaN(null) === false are the expected behavior. And as this behavior is in the specifications of Ecmascript, it does not vary according to the environment.


And, as you might imagine, the algorithm of ToNumber can be observed in action by calling the function Number() - that’s because when the Number is called as function, it performs a type conversion:

console.log('undefined:', Number(undefined)); // NaN
console.log('null:', Number(null)); // 0

  • 1

    Now it remains to be seen who decided undefined is Nan and null is zero...

  • 1

    @hkotsubo I was putting a reference of the definitions of undefined and null in the answer, but none of them facilitated this interpretation that one is NaN and the other is 0, so I decided to remove hahaha. But out of curiosity, you are here: Undefined primitive value used when a variable has not been assigned a value and null primitive value that represents the intentional absence of any object value

  • 1

    Yeah, by the definition, maybe make sense. If it has no value, there is no way to convert to number. And if it is "absence of intentional value", the zero would be the value "similar", because it is the number that serves to indicate that it has nothing...

2

The typeof of null is object, can behave in several different ways, causing this type of behavior. This happens due to the functions prototype of an object, for example, implementing toString an object may behave as string in certain cases.

To better understand this case, understand that the isNaN will receive everything as Number(valor). In that case, Number(null) will return 0. That’s why isNaN returns false.

Read isNaN(valor) as isNaN(Number(valor)).

But this is curious, although Number(null) return 0, null is different from 0 even with comparison ==:

console.log(null == 0); // false


That’s why I like Typescript rs. Maybe with typing you don’t go near that kind of trouble.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.