This course is out of date and does not reflect Frontend Masters current standards. We now recommend you take the JavaScript: The Hard Parts course.
Transcript from the "Comparison Operators Explained" Lesson
[00:00:00]
>> [MUSIC]
[00:00:03]
>> Alexis Abril: We briefly touched on by reference and by value, what that means, have you guys heard that term before? Has anyone not heard that term by reference or by value before, passed by reference, passed by value? Okay, we're good on that front? So we're gonna talk about === versus ==, let's observe, we have this code on the left side.
[00:00:24] We have two strings or two pointers to two primitive strings but they're the same string the same you know actual string. Then we're gonna do a comparison str1===str2. What this is going to do in memory, you can see here on our right side we have our n str 1 and 2 pointers.
[00:00:43] They're pointing to our two primitive strings of memory, the first one in 2001, and the second one in 2101. What this is gonna do is it's gonna find those two primitives in memory and compare the actual values that those have. This is what we call comparison by value I guess, when we're passing by value, it's gonna look at the actual value that's held at those locations.
[00:01:10] So, this will compare those two, does hi equal hi? That's true, so ===, this will return TRUE. Question? Interjection. Come on in.
>> Speaker 2: Interjection, a little qualification here. The two strings very likely would only be one string in memory. This is this is a rule of, we like to say that every time a string is created, a string object is created in memory, right?
[00:01:35] But in reality, JavaScript interpreters probably, it'll only probably create one string. Is again, just our rule of thumb versus what happens in reality. Primitive types like strings are, you could almost think that there's only one hi ever created in reality. But, I think it's better to actually think like they're both created and that there's gonna be a comparison like this.
[00:02:01] Cuz there could be two hi that's created in some, there's there's nothing preventing the language from doing that, just what happens in most browsers would only create one hi in this case.
>> Alexis Abril: Be sure.
>> Speaker 2: We don't think about per load just the weird thing is like primitives, is they're both passed by reference and passed by value in some place.
[00:02:25] Because you can't actually modify a string, you can't restate a string like hey, change this second bit of a hi, or six inches second byte of a hi to a capital I. You can actually do that and keep the same string in memory. You'll just get back a brand new string.
[00:02:48] So the reality of primitive types like this is much more complex. There's a lot to learn there but again I just wanna say the rule of thumbs that we're giving will get you the right answer, just there's a lot of optimizations underneath the coding.
>> Alexis Abril: Yes, yes.
>> Speaker 2: You could learn about, but there's really only if you're a geek do you need to learn about it.
[00:03:11]
>> Alexis Abril: Be sure I know we mentioned that just with the discussion of the VA developer, that's where this all really was born from. Is we had a core VA developer who was like no this is, we would never do this, this is so inefficient, we just create what is hi.
[00:03:22] We'll be sure to post that just because it's there. It's a really good discussion where you have someone with intimate knowledge when the core team members over VA talking about how they set this stuff up in the real world. Not in our we're learning how to create a browser world, so cool.
[00:03:42] Okay now this is with primitives. With objects, it's gonna do things just a little bit different. So we have obj1 is this empty object, obj2 is empty object, we have pointers to their respective addresses in memory. And from, at face value, I would do the same thing. I would say hey these objects have the same actual structure, they have the same values, they're both empty in this case, they should result to equal.
[00:04:11] But because they are composite types, what this is gonna do, is it's going to check by reference, it's gonna check the actual address of where these objects are in memory. And since these are two different objects, two new objects created in memory, they have two different addresses. We're not going to go through and check all of its attributes.
[00:04:31] We're just gonna say, are you at the same spot? You're not, you must be two different things, this is gonna return false.
>> Speaker 3: Can you give that same example using a ==, like how the memory works?
>> Alexis Abril: Yes I can but, I can also, come on, second time's the charm.
[00:04:58]
>> Alexis Abril: I can show you what would happen in a == scenario. So that was ===, triple equals in a primitive case, we're gonna compare the values at the two addresses. In a composite case when compared the addresses of what's a left or right side. What happens in a == case?
[00:05:17] This is the the logical path that a == comparison is going to take. You're gonna take the left == the right and it's going to run through each of these in order to produce, recursively to produce, some type of end result. So let's talk about this. Rather than take the two objects, let's do something really weird.
[00:05:42] Let's take that crazy case where we had a boolean compared to an object with a toString. We used a valueOf in the example we're gonna use a toString in this example, returning our 1. Why this returns true? So let's walk through this. The first thing we're gonna come to is we're gonna say hey, are these two types the same?
[00:06:01] In this case they're not, one is a boolean, one's an object. So it's gonna say no. So the next step is gonna say hey are both null or undefined and see and say no that's not that's not the case we're at yet. Do we have a string being compared to a number?
[00:06:19] Again false. Do we have a boolean being compared to anything? This is a condition we can pass like okay now we're on the right track. Let's pass this into our little state machine, and we're convert our Boolean true, it's gonna spit out a 1. That's the only thing that we can really do in the state machine.
[00:06:40] We're gonna take true, we're gonna convert it to a 1. And then we're going to recursively call the same == comparison, except now we're gonna say 1 compared to the object toString, function 1. Then we start this whole machine over again, are the types the same? Nope, are they both null or undefined, still not there yet, do have a string equal to a number?
[00:07:04] Not quite, do we have boolean equal to anything? No, we're gonna get to go one level deeper this time. Do we have an object equal to a string or a number? Yes this is the case we're at. So what we're going to do is in a call toString or a valueOf, we happen to have a toString method on our object.
[00:07:20] And we're gonna compare the number or string, our case is a number to whatever is returned from these methods. So now we are gonna get 1 == "1" because we happened to pass an object with a toString function when invoked will return a string 1. This is our clever little trick.
[00:07:45] We're gonna start the whole process over with 1 == "1". Are the types the same? Still no, both null or undefined? Do have a string equal to a number? Yes, so now we're gonna go back to our state machine and what we're gonna do you can see down here at the bottom we have a string.
[00:08:05] We're gonna convert the string to either a number or not a number. In this case the string 1 can be converted to a 1, so we're gonna get 1 == 1. We're not done yet, we have to start the whole mission over again. 1 == 1, are the types the same?
[00:08:23] Yes, call === internally. That's what this machine is gonna do and eventually, now 1 === 1. It's gonna do the comparisons and say yeah you're the same thing. Finally, after I measure how my slides that was to get through this machine that many times. This is why it's a performance hit.
[00:08:42] And why you're gonna get unexpected behavior. Expected if you have this kind of memorized and internalized, which I don't. But still gonna be, you don't wanna base any kind of validation or any kind of condition logic at all on this. This is exactly why you don't use ==.
[00:09:04] The performance footprint of a ===, this is the graph. Are the types the same? Yes or no, if they're not saying that is false, stops right there. These types are the same is it a primitive? Compare the values, not compare the addresses and then you're done. This is complex as it's going to get for ===.
[00:09:26] == is that crazy state machine to answer your question.
>> Speaker 4: So would you never use the ==?
>> Alexis Abril: I never use the ==, ever, do you use ==?
>> Speaker 4: When I want to compare null to undefined. That's a good place [CROSSTALK] So they don't have the write.
>> Alexis Abril: Even try to write it out in the type of you know the one you've already.
[00:09:54]
>> Speaker 4: So what you're going to [CROSSTALK]. No I want to write Foo === null or Foo === undefined. It's just nicer to write Foo == null or undefined, right? Then you get both.
>> Speaker 4: And you'll see that in a lot of libraries, it's kinda an accepted. There's an exception in JSLint or something for doing that.
[00:10:22]
>> Alexis Abril: A flag, you mean for allowing it.
>> Speaker 4: Yeah, yeah.