NaN is mildly mind warping. Can someone explain?

Hi campers,

I was working on Falsy Bouncer and managed to figure it out with the help of MDN https://developer.mozilla.org. I think I understand why the code works but why does NaN not equal NaN?

Why does NaN == NaN or NaN === NaN evaluate to false?

I normally explain it like: So NaN is a value JavaScript returns (it isn’t something you would create yourself) when it finds something it expects to be a number but isn’t. So for example:

> Math.round('I am a number, honest I am')
NaN

So what it does in that situation is it tries to convert the value to a number and fails. It doesn’t keep any kind of record of what the original value that actually caused the NaN actually is, only that it is NaN - the end value is just “something that should be a number bit isn’t”. Logically that means there are infinite possiblities as to what it actually is - one NaN could be caused by the string 'hello' interacting with a Math function, and one could be caused by '7e26ed63-b435-4537-aa73-e8e5d532f863' and so on, JS has no idea, it only cares that it isn’t a number and it can’t do a calculation. So one NaN can never equal another NaN; it has no value besides being NaN so can’t be compared positively to another NaN.

Another way to think of it, leading on from that, is that NaN is a description of something that happened, it’s not a value like 1 or 'foo' that has a concrete representation

1 Like

It’s kind of like in a story where the hero tells the stupid bad guy “My name is No-man” and then later when he attacks and all the other bad guys hear the ruckus and go “Who’s attacking you bad guy friend?” and the stupid bad guy is like “No-man is attacking me!” so they say “Stop screaming then, you idiot.” Nan is “No-man”.

Sorry. I haven’t had coffee yet.

Basically, NaN isn’t really a thing that you interact with. It’s just JavaScript’s response to being told to do something to not-a-number that can only be done to a number.


Now. Putting all that aside, I’m going to let you know that you are making this much harder than you need to. This challenge is about teaching you what “falsey” means. Anything that is “falsey” will act the same as false in a logical condition. It also will return false if cast to a Boolean. You don’t need to worry about the list of the 5 values that are falsey and make them be false. That’s reinventing the wheel. You can just use the fact that JavaScript already treats these values as false in those circumstances.

1 Like

Thanks DanCouper, that’s a good way to think about it. I guess in other words, this NaN could have been anything, and that NaN could have been anything so really it’d be hard to say they are equal. We don’t know the cause for NaN.

[quote=“ArielLeslie, post:3, topic:172190, full:true”]
It’s kind… Nan is “No-man”. [/quote]

Sorry. I haven’t had coffee yet.

I haven’t yet either as I write this but I did picture this movie called Hollow Man…

Thanks for the advice. Some food for thought. I’ll have to go take a second look at my code. It works but thinking about what your saying perhaps I can simplify. This is the code inside the bouncer function… what could I do to simplify?

function filterFalsy(val) {

switch (val){
case “”:
case false:
case 0:
case null:
case undefined:
return false;
default:
return true;
}

}

var notBounced = arr.filter();

return notBounced;
}

Spoiler
function bouncer(arr) {
  // Don't show a false ID to this bouncer.
  return arr.filter((item) => item);
}

Try this in a console:

Array(16).join('string' - 1) + ' Batman';
3 Likes

Thanks! That is much cleaner. I’ll have to read the (item) => item notation. I saw that in the docs but didn’t dig too deep into it. Much appreciated.

Thanks Soupedenuit! I’ll have to give this a try too. Appreciate the knowledge sharing.

(item) => item is the same as function(item) { return item; }. Since it’s a filter function it gets treated like function(item) { return Boolean(item);}. (Because filter is looking at the truthy/falsey-ness of the return value.)

1 Like

The Javascript spec basically says that you should not use == or === to evaluate NaN. Instead use the isNaN() function.

Also bear in mind that NaN is NOT one of the primitive types. It is of type number. So when you have an operation that should return a number but does not, JS can return an entity with the correct type.

1 Like

On a related note, if you’re not familiar with the Number() method it is super useful for when you’re using numbers extracted from strings to do calculations. I often use it to ensure my numbers are numbers, thereby not relying solely on type coercion.

1 Like

Further from what @Soupedenuit said, there is a shorthand that you might see - you can use the unary + operator to do the same thing:

> Number('123')
123
> +'123'
123
> +'123.456'
123.456
> +'hello'
NaN

It saves quite a bit of typing if you need to ensure a lot of stuff that is coming in as strings get converted to real numbers, which happens in particular when you read values from HTML attributes.

In a related note, if you want to ensure that the numbers are all integers

> 1 | 0
1
> 1.234 | 0
1
> '12.34' | 0
12

(this is how the precursor to WebAssembly, ASM (and Emscripten, the C/C++ -> JS compiler, amongst other things), ensures actual integers even though JS only has floating point)

2 Likes

Holy Adam West batman! I see, so because you subtracted 1 from string you performed a mathematical operation on it which should result in a number but it’s not, so NaN.

:man_facepalming:LOL, thank you. That is quite a few lines of code I didn’t need. I get the falsey <-> filter interaction.

That is correctomendo.