Check out a free preview of the full Deep JavaScript Foundations course:
The "Negative Zero" 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 reviews why JavaScript has two zeroes, a normal zero 0, otherwise known as a positive zero or +0, and a negative zero or -0.

Get Unlimited Access Now

Transcript from the "Negative Zero" Lesson

[00:00:00]
>> Kyle Simpson: Moving on to our next special value. We'll talk about negative zero. You're gonna have to suspend some of your mathematic belief for just a moment, and pretend that there is such a thing as a negative zero. And if in that hypothetical world there is, can we all at least agree that if there is a negative zero, basically the only way to get a negative zero would be to do a multiplication or division with a negative value and zero.

[00:00:24] Because it wouldn't make any sense to add up or subtract to a negative zero. It's not like negative three plus three would be negative zero or something like that. So multiplication or division would be the only way that we could result in such a value, okay? So if we were to take zero and divide it by negative three, it should result in this negative 0 value should one exist.

[00:00:45] And it turns out if we test for it, we get true. But unfortunately, if we test for the regular zero, we also get true. So line 3 lets us know there's something weird going on. How can it both be negative 0 and 0? And many people stop at line 3 and just assume well, okay, I guess there isn't a negative zero, it's just ignoring that minus sign.

[00:01:04] Some of you may have been confused by this. I certainly was confused for quite a while. When you see negative 3 there on line 1. You probably think to yourself, JavaScript treats that as a number called negative 3. But that's not how JavaScript actually parses it. JavaScript actually parses it as the number 3 then it's operated on by the unary negate minus operator to produce the actual negative 3 value.

[00:01:35] There is no such thing as a negative 3 literal. There is the 3 literal and then the minus sign is an operator in front of it, and I find that bizarre. It's part of the reason why even in syntax highlighting, you see that minus sign highlighted as an operator as opposed doing the same color as the literal, because JavaScript doesn't actually treat that as a literal.

[00:01:54] What that means is when we deal with negative zero, we are operating on that zero. It's not like negative 0 is just ignored, it's that we are taking the regular 0 value on line 2 and negating it. So we are producing the negative zero value. But how is it that foo can be triple equal to negative zero and to regular zero?

[00:02:13] Well, the problem is not that there isn't a negative zero, but that the triple equals operator lies to us. And it doest that on purpose. If you read the spec, it literally says if there's a negative zero, return true. So y isn't lying to us. Well, this is kinda what I was talking about earlier.

[00:02:33] In the early days of JavaScript, there was a design aesthetic that was basically try to be as forgiving as possible, try to hide as many warts as possible that might confuse people. And if you think about the earliest use cases, many people were using JavaScript to translate those Java plugins into web forms like e-commerce ordering forms and things like that.

[00:02:51] So I can imagine one of this cases that they really wanted to avoid was somebody showing up within their quantity field on an e-commerce forms, negative zero for the quantity zero. Cuz that doesn't make any sense, right? And it doesn't make any sense to a user. So how could we end up with a negative zero here?

[00:03:08] So, what they basically did was when they said all the different operations that could operate on a negative zero, just make it pretend as if you were operating on a regular zero. In other words, try to hide the fact that there is a negative zero. Which is why the === operator here works.

[00:03:24] Even when negative zero is compared to regular zero, it actually says true. That's a strange choice, and it's even true if you try to coerce it to a string. If you try to take the negative zero and call two string on it, or negative zero and pass it in the string function then you're gonna get regular zero instead of negative zero, which is bizarre, right?

[00:03:47] But again, it was because they were trying to hide the fact that this exists. So in all of our cases of how we wanna try to test for the negative zero, it fails for us. Even if you try this in your browser, and you type in foo. Up until about a year, a year and a half ago, it would print regular zero in the browser console instead of negative zero.

[00:04:10] And then it finally started passing it, because I complained enough to the browser vendors, the development tool teams. Because I'm a teacher and I spend a lot of time teaching people in web developer consoles, it's frustrating to me when the web developer console doesn't work the way it ought to.

[00:04:26] And this is an unfortunate fact, the web developer console is not a true, complete, totally reliable JavaScript environment the way you might expect. You might think, I just open up my console, it's a clean, empty page. I have a fresh JavaScript context, it's gonna behave exactly as if I wrote my program this way.

[00:04:44] That's not the case. The console is not down by any spec, and they can do whatever they want. So it's more appropriate to think of your console and JavaScript-like than actual real core exactly the same global JavaScript, okay? As a matter of fact, node is also JavaScript-like. Not actually true, real, and complete in all possible ways.

[00:05:07] Cuz it turns out that node does a bunch of funky stuff like wrapping your code in module definitions and things like that. They change the way you might expect actual just regular JavaScript, the standalone line of code to work. So there really is only one environment that you can write a line of code all by itself, and guarantee that it's gonna work exactly the way that core JavaScript expects.

[00:05:30] And that is to put it in its own file and load that file in a webpage, that's it. Every other environment, you're gonna need to have that caveat in mind, that they might be doing funky stuff like changing the way something prints, because they think it's more friendly to a developer or something.

[00:05:47] This was basically lying to developers and that was my case. I said, quit lying to developers, that's not helping anything. Tell them the truth, okay? I fought this battle about a dozen times on different topics and I've had about a 50, 50 success rate of convincing them. Stop doing stupid stuff that makes it hard for developers to understand what they're doing, okay?

[00:06:08] [COUGH] I actually had a member of the Google Chrome developer team tell me, we don't want the console to be in an environment where people author JavaScript in. As counterintuitive that seems, that is not a design goal of theirs. So when it doesn't behave like a JavaScript authoring environment, they're like works as intended, closing the book, okay?

[00:06:29] So just keep that in mind.
>> Kyle Simpson: So, if we can't test for foo being negative zero in any way that we have meaningful to us. The stringification, the equals, all these systems are gonna lie to us. How do you think we can test for negative zero?
>> Speaker 2: Check for reciprocal of its negative infinity?

[00:06:48]
>> Kyle Simpson: Turns out if we divide it into 1, we're gonna get negative infinity. That's the only way we can get negative infinity with the division, is if we add a negative 0. We need to check to make sure it's one of the two zeroes. That's what the ===0 check is on line 2, cuz negative infinity would also also equal negative infinity.

[00:07:10] [COUGH] But we need to make sure we, if it is one of the two zeroes, then we can divide it into one and get a negative infinity. So this is a reliable check for negative zero, okay? Now, you might be wondering, why on earth, this is a bunch of academic stuff, why on earth would I care about a negative zero?

[00:07:32] There are some mechanisms that have been in place, and I have legitimately actually used this once in real code. There are some mechanisms, which encode into a number multiple pieces of information. In particular, they will use the magnitude of the number, the size of the number, to represent something like how fast something is moving in animation, for example.

[00:07:54] And they'll use the sign of the number to encode the direction of movement. I use this in a navigation sort of app, where the number represented how fast the car was moving on this map as it was being plotted. And then the direction was encoded by the number, wasn't moving left or right, okay?

[00:08:12] So think about the moment when it goes to zero. If you were to lose the sign, it would lose the orientation of that little car. I wouldn't be able to know if it was facing left or right, where was it moving when it stopped? What direction was it moving?

[00:08:27] I'd lose that information. So being able to encode direction as part of this value in the sign is kind of an important thing, and we don't want to lose that information when we go to zero. That's one example of wanting a negative zero for capability's sake. And I'm not saying that's gonna be a common thing across all your applications, but it should exist and we should be aware of that.

[00:08:53]
>> Kyle Simpson: All right, now both the NaN check and the 0 check that we're talking about, they feel a little bit contrived. And so they added a new mechanism in ES6 called Object.is. I do not like where they put it. I think it's a terrible idea to put it on the object namespace, because it implies that we're dealing something with objects.

[00:09:17] And it reinforces a misconception that people have said for 22 years, that everything in JavaScript is an object which is nonsense. So I don't like that they put it on Object, but the is function actually turns out to be kind of interesting and useful. The is function is kind of a quadruple equals, okay?

[00:09:37] If you think about double equals is doing one thing, and then triple equals seems to be a more strict check. But it still lies to us on the topic of negative zero and on the topic of NaN. The object that is, is the quadruple equals which doesn't do any lying.

[00:09:51] My little anecdote for this is I don't know if anybody remembers. But the TV commercials for, there's a brand of men's shaving razor called Mach or something like that. I don't know, years and years ago, they had the Mach one and had the single blade. And then it was a big deal when they came out with the Mach two and it had two blades.

[00:10:09] Then a year later, there came out with the Mach three and it had three blades. And you're like, all right, it's getting a little bit ridiculous, right? And then they had like four, five, six, seven. I think they're on like Mach 28 now or something, they just keep adding more blades.

[00:10:20] So we just keep adding more equals until we get really quality in JavaScript. It's kinda the four equals. [LAUGH] Now, should you use Object.is instead of the double or the triple equals? In general, no. In general, do not use this, because it is not gonna more clearly communicate, and it's also probably not gonna be necessarily as performing.

[00:10:42] But in the specific case of NaN and negative zero checking, you absolutely should use the Object.is, okay? So for NaN or negative zero checking or both, use Object.is because it will well, and true, and faithfully tell you the answer to your question without any lying whatsoever.
>> Kyle Simpson: All right, so those are our special types, our special values within the perimeter types.

[00:11:08] Quiz, baz = 2, what is the type of baz?
>> Kyle Simpson: Quote number, good, right? Now, I say var baz again and then I say type of baz on line 4, what is the type of baz?
>> Students: [INAUDIBLE]
>> Kyle Simpson: I hear different answers. Only some of you are correct.

[00:11:35] Who thinks it's quote undefined? Who thinks it's quote number? Who thinks it's something other than those two? Okay, so the trick here is that we think of line 3 as redeclaring baz. And people generally will consider that to be recreating baz and creating in its undefined state. There's no such thing as redeclaration in JavaScript, okay?

[00:12:01] So var baz on line 3 is a no op, it does not actually do anything at all to the baz. The compiler would see that and ignore it as a no op operation, okay? In which case, line 4 is exactly the same as line 2, baz is still in its existent state.

[00:12:17] That's why we're getting quote number. And, what about line 5? I say baz = null. And then line 6, what's gonna be the type of baz?
>> Students: Quote object.
>> Kyle Simpson: Quote object. Instead of quote null like it ought to be, it's gonna say quote object. All right, now line 8, [COUGH] I take a string, the string baz, and I multiply it by 3.

[00:12:35] There are some languages, for example, Ruby where the results of that will be repeating the string, baz, baz, baz [LAUGH]. That's not what JavaScript does. JavaScript defines multiplication as only numeric. So, what's gonna happen with the value in line 9?
>> Students: Add the number.
>> Kyle Simpson: Okay, it's gonna try to coerce, quote baz into a number, that's gonna fail resulting in Nan.

[00:13:02] We're gonna have the invalid number Nan, and Nan times 3 is still gonna be Nan. Now, but what about the type of baz on line 10?
>> Students: Quote number.
>> Kyle Simpson: Quote number, okay? Baz = 1 divided by 0 on line 12, what is the value of baz in line 13?

[00:13:19]
>> Speaker 4: Infinity.
>> Kyle Simpson: Infinity. And what is the type of baz?
>> Speaker 4: Quote number.
>> Kyle Simpson: Quote number. Infinity is a number. I've actually had people suggest it should be something other than a number. It's definitely a number, okay?