Why does NaN = !NaN return true?

990 views Asked by At

NaN is one of those vestigial implementations of questionable origins, but for the most part I get it. However, I typed this into a Node prompt today and couldn't really make sense of it...

NaN = !NaN
> true

Is this simply returning the evaluated result of !NaN? This makes sense, but I'm surprised that there's not an error when attempting to assign NaN to another value.

Note: this question is about this specific syntax structure; there are a lot of questions related to NaN and isNaN out there but I couldn't find an answer after googling. Thanks to Ori Drori for the best answer thus far.

console.log(NaN = !NaN);

5

There are 5 answers

2
Ori Drori On BEST ANSWER

You are assigning true to NaN instead of comparing NaN to !NaN using === or ==, so the operation returns the assigned value -> true. Javascript ignores this assignment silently because NaN is read only.

console.log(NaN = true);

// NaN hasn't changed
console.log(NaN);

If you'll add use strict to your code, JS will throw a read only error instead:

'use strict';
NaN = true;

1
fafl On

Javascript is really weird: When you write

NaN = true  // true

which you basically do in your statement, you get "true". This is the same behavior as when you write

a = true  // true

where the right side of the assignment is returned. But if you add var and write

var a = true  // undefined

then nothing is returned. Also if you replace NaN with an expression that evaluates to NaN, for example

1/"a" = true  // error!

then you get a ReferenceError. I recommend to never use the return values of assignments. The behavior is inconclusive and your code will be hard to read. You can enable "strict mode" to check this for you.

0
Eterm On

= is the asignment operator. == and === are comparison operators.

NaN == !NaN
false
NaN === !NaN
false

Perhaps more surprisingly:

NaN  == NaN
false
NaN  === NaN
false

For more about NaN: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/NaN

0
AudioBubble On

Using = operator, you assign the value to a variable. However, what you don't know is by doing that, it returns the value of what is being assigned. Typing:

v = 1

in a JavaScript REPL will display 1, because that is what was assigned to v. So, doing:

NaN = !NaN

Will assign the opposite value of NaN to NaN itself. Since NaN in boolean is false, then !NaN in boolean must be true.

0
Eddie On

Try running Javascript in a strict mode to avoid most of the problems.

NaN, null, false, "", null, undefined, 0 etc they are considered as falsy values (remember falsy !== false) in javascript, no matter you use a strict mode or not.

// 'use strict';

console.log(!NaN);       // true
console.log(!null);      // true
console.log(!false);     // true
console.log(!"");        // true
console.log(!null);      // true
console.log(!undefined); // true
console.log(!0);         // true

It is true in Python as well, except for NaN. For example,

print(not False)        # True
print(not None)         # True
print(not float("NaN")) # False
print(not "")           # True
print(not 0)            # True

Source of confusion When we use multiple languages sometimes it can be a source of confusion.

For example,

In Python 'cat' in ['fat', 'cat', 'rat', 'hat'] returns True.

In Javascript 'cat' in ['fat', 'cat', 'rat', 'hat'] (exactly the same piece of code) returns false no matter you use a strict mode or not.

In Python print(not []) returns True.

In Javascript console.log(![]); returns false.

This is one of the reasons why I always love to use debuggers, REPL etc no matter how simple the code is.