Check out a free preview of the full Deep JavaScript Foundations course:
The "Special Values" Lesson is part of the full, Deep JavaScript Foundations course featured in this preview video. Here's what you'd learn in this lesson:

Kyle discusses special values in primitive types: NaN, Infinity, null, undefined (void), and negative and positive zero (+0, -0).

Get Unlimited Access Now

Transcript from the "Special Values" Lesson

[00:00:00]
>> Kyle Simpson: Now there's some values within the primitive types that we should pay attention to. Some values that we wanna look at. Specifically we're gonna look at NaN, which is transliterated as not a number. Although we'll find out in just a moment. That's a really terrible name for that.

[00:00:15] Both infinity and -infinity, not all languages have that but JavaScript definitely has a representation of both infinity and -infinity. Some of your intuition about those might not be the same like I know we have some math folks in the crowd. It may anger you to think how JavaScript interprets infinity and things like that, but like for example, you can technically add up numbers, and when you overflow the 54 bits, it just goes to infinity.

[00:00:40] That's probably super annoying to math folks. [COUGH] But these are special values that we should pay attention to. Null is a value, as well as a type. It's the only value in the null type. Undefined is the only value in the undefined type. And I mentioned here, the void operator.

[00:01:01] That's an important operator, but it doesn't get any attention. That's how you can take any value and produce the undefined value from it. So it takes whatever you put in. Say void true, void function, whatever. You're gonna get back undefined. Now there's not a lot of uses for that, but there's a couple places that I've used that in the past.

[00:01:18] And then again, something that's gonna annoy the math folks in the audience. There's both a +0 and -0. Now you may think, well, this is crazy. Right off the bat, see, we have proof that JavaScript was poorly defined. Why on Earth would they come up with this kind of craziness?

[00:01:33] None of this is JavaScript invented. Everything that I just talked about, the + and -0, and the positive and negative infinity, that is true of all IEEE 754 compliant languages. Which include Ruby, Python, and about a list of 12 or 15,000 other languages that are out there. Most languages actually these days are created to be IEEE 754 compliant.

[00:01:59] And JavaScript is just one of them. So whenever we complain about 0.1 plus 0.2 is not equal to 0.3 or whatever, has nothing to do with JavaScript. That's on IEEE. They chose the floating point representation that can't correctly represent numbers in memory that are floating point numbers. That's on IEEE, and all JavaScript did was say we're gonna be compliant to IEEE.

[00:02:22] The exact same thing is true. Some languages try to hide it a little bit more than others. But this is just all basic computing science, discrete mathematics stuff, okay? So -0, even though that sounds strange and it's counterintuitive from a mathematic perspective, is something that's required by IEEE.

[00:02:40] And it turns out there's at least one or two small used cases where it's helpful, so we're gonna look at that in just a moment. NaN. Supposedly, NaN stands for not a number. Let me tell you where NaN actually comes from. Any time you try to take a value and convert it to a number, and that conversion fails, the resultant value is to tell you this was an invalid number.

[00:03:08] That is the only place that NaN comes from. So if we look at this line 1, we see the divide operator. The divide operator specifically designed to do mathematic division, which means it needs both of its operands to be numbers. If you give it something that's not a number, we kick in this thing that we're gonna talk about a lot more.

[00:03:28] This implicit coercion thing, it's gonna try to convert it to a number. And when you try to convert "a" to a number, because we're not telling it what base, it's gonna assume base ten. And "a" is not a valid character in base ten, so it's going to fail to convert it.

[00:03:45] Which means it's going to produce this special value. We have a term in computing science we call the sentinel value. A value that represents some special characteristic. We need to give it a special label, if you will, so that you know there's something special about it. In this case, the specialness is, it's invalid.

[00:04:08] So what are some other options that we could have used? If we were to try to go back and backseat drive on design and language, what could he have done here? If you try to convert something to a number and it didn't properly convert to a number, what could we have done?

[00:04:22] You could have resulted in false. But that would be super weird, that you tried to do a numeric operation and you ended up with a Boolean value. That doesn't make any sense. Null or undefined are similarly weird results from that type of operation because they are, in themselves, distinct different primitive types.

[00:04:43] Really, the only resulting type that a number operation should produce is a number. Would we all agree with that? I hope so. If you're gonna do a numeric operation, and you need a result, by well better be a number. Otherwise, what are we doing here? Why do we even programming?

[00:05:01] Okay? Was it just like programming by guessing? No, that would be terrible design. So what's the only other option if it needs to be a number but it failed to be a number? What's the only other option besides something like the special NaN? Well we could have thrown an exception.

[00:05:16] As a matter of fact, many languages do. If you try to convert "a" to an integer in c, you get an exception. If you try to do it in Java, you get an exception. Why didn't JavaScript choose to make an exception here? Well, you may not know about the history of JavaScript, but JavaScript didn't get the try catch and exception handling until four years later.

[00:05:40] First four years of JavaScript did not have a try catch or any notion of handling exceptions. So this would have been a fatal, crash your program, kind of an error, unrecoverable. That's kind of unfriendly design. So JavaScript chose as a design aesthetic, early on, to try to be as forgiving as possible.

[00:05:57] We're gonna see this design aesthetic over and over and over again. That there was an intentional decision at the beginning of the language to say, let's try not to just frustrate the crap out of people where there's just error after error after error and there's no hope of getting anything done.

[00:06:12] JavaScript in a sense was playing kind of a marketing game. They were trying to convince people in real programming languages. Hey, come try out this toy language called JavaScript. One of the best ways I can think of to attract people is to not frustrate them by they're being a nuance like you need a semicolon here or you need a comma there or whatever.

[00:06:31] Try to be as forgiving as we possibly can while still being sane. And implicit coercion is a nod to that, as a matter of fact. It's a nod to saying instead of throwing an exception and just slapping somebody down and saying sorry, try again. We're saying let's figure out what's the best that we can do.

[00:06:46] Is there any kind of guess that we could make? You did something dumb, but could we try to recover it? Instead of garbage in, garbage out, it's like garbage in, recycled material out, right? Let's try to figure out the best that we can do here. So, we needed a value to represent that this number conversion failed.

[00:07:03] And NaN is that value. NaN is the value that says, number conversion failed. Okay? So it hasn't even happened that the divide has occurred on line 1. It's just the case that we tried to convert and that failed. So now we have a NaN divided by 2 and NaN with anything else is gonna produce NaN.

[00:07:22] NaN times NaN, NaN divided by, whatever you do, if NaN is part of it, NaN is gonna come out. It's just like the invalidating [COUGH] of all values. So of course a has the value NaN on line 3. And if we ask for the type of a, we get "number" because that's the only sensible result is that we did a numeric operation, we got a number back.

[00:07:44] But now we find the conflict with calling NaN not a number, because we say the type of not a number is number, and that makes no sense. The only proper response here, is to stop calling it not a number. That's not what it should be referred to. If I could go back and change it, I'd call it the invalid number, cuz that's what it is.

[00:08:05] I call it IN instead of NaN. I'd call it the invalid number, okay? That's what it really is. Now, NaN, again because of IEEE, this is all required by IEEE. NaN, [COUGH] there's actually a bunch of NaN values and the way you get at them differently, like the bit patterns form can be different depending on your scenario, whatever.

[00:08:28] So there's a requirement in IEEE that NaN is never equal to itself. Which sounds bizarre because it's literally the only value that I'm aware of in all of computing science, that does not have the identity property. It is not equal to itself. We're gonna actually make use of that identity property in just a moment, but NaN is never equal to itself.

[00:08:49] So if you wanna test for NaN, you're gonna need a special privileged utility. And they gave us isNaN. It's built into the global space. We get isNaN or window.isNaN or global.isNaN. Supposedly, it just tests to see whether or not the thing you pass in is the NaN value.

[00:09:04] Unfortunately, there's a fatal flaw in that original utility. A bug that we can't fix, cuz we already just discussed, as soon as we make mistakes. Let's write them in stone. We can't fix this bug. Because if I pass in isNaN and I pass in "foo". Now let me ask you a question, is "foo" a number?

[00:09:25] No. Is it not a number? You see the difference? See the problem with using not a number as our description? It is not the special, sentinel, invalid number type, and yet we're gonna get true back from isNaN because you know what isNaN does? If you pass something that's not already a number to isNaN, guess what it does?

[00:09:47] It tries to convert it to a number first. And then check to see if it resulted in the NaN. Here is a place where that conversion was a pretty terrible idea. We should never have tried to convert it. You should have just taken it and checked that and be done with it, right?

[00:10:03] But unfortunately they automatically convert first before checking so by the time it checks it, we've already converted "foo" to the NaN value and it says sure, that's a NaN. Fatal flaw. So this is a bug in isNaN. Now, thankfully, we finally decided to fix it by making a new isNaN in a different space, Number.isNaN.

[00:10:25] Number.isNaN does exactly what we want, which is it checks only the value, doesn't allow that coercion. This is what we call the polyfill pattern. You notice I've got an if statement that checks to make sure it's not already defined. And that code would only be true in older environments, so we're basically patching an older environment to have something that's been added in newer environments, like for example, ES6.

[00:10:46] And you notice what is NaN does here, it just says typeof num == "number". So at first, checks to make sure it's already of that number type and then it uses the isNaN. So really the true NaN is only gonna pass if both of those are the case.

[00:11:05] So that's an easy way of polyfilling. The new built-in Number.isNaN. If you're using regular isNaN in your checks, switch to using Number.isNaN so you don't have those bugs, okay? Cuz if you're not already accounting for this problem, the fact is you have a bug in your current JavaScript programs, even if you've never been bitten by it.

[00:11:24] Just a bug that's been built into JavaScript. Turns out there's an even easier, and perhaps even cleaner way of testing for NaN. NaN is the only value that's never equal to itself. So if we test the value to be equal to itself, NaN is the only one where that will fail.

[00:11:41] All right, so that is NaN and that's how we deal with the NaN. Again, we check to see if these values, not equal to itself is the only one without that identity property.