Transcript from the "this Keyword" Lesson
>> Kyle Simpson: We will continue on in our discussion of scope and closures. We're gonna take that interesting detour where we're gonna talk about the this keyword. Which might, as we start to look at this it might look a little strange, why are we talking about that right in the middle of scope and closure discussion?
[00:00:40] So to explain the this keyword, our sort of what you need to know definition, we're gonna say is that, every function, while it's executing, has a reference to its own current execution context. And we'll call that reference the this keyword. Now, technically the execution, we're fibbing a little bit, because technically the execution context includes more than just the this keyword.
[00:01:01] There's more to it, there's your local variable stack and other things like that. But for our purposes, all we care about is that this binding, so our execution context, we'll say, is our this keyword. What do we mean by that execution context? What we mean by the execution context is where the function is called, or how the function is called when it's called.
[00:01:22] So we're gonna need to go back and look at that callsite. And to draw your attention back to this diagram before, we saw the lexical scoping model, was like taking the elevator or the stairs of this building on the left hand side. What we're gonna see now is this this mechanism that we're gonna look at.
[00:01:38] It's kind of like, metaphorically, telling us the address of which building on the right to go into. So you got a bunch of buildings down town in your city. And each one of them has a different address and you need to meet with somebody. Well the first thing that they're gonna have to tell you is the address of the building to go to.
[00:01:59] Before you can even go into the first floor of the building and start looking for their office, you're gonna have to know their address. So this mechanism that we are going to talk about, that is the this keyword, is going to essentially tell us the address of which building to be looking at.
[00:02:12] And it is, the rest of today we will expose what the rest of that building metaphor is, but right now we're talking about how do we figure out which first floor to go into. All right, so there are four rules for how the this keyword gets bound. And they all depend upon what we call the callsite.
[00:02:30] The callsite is the place in code where a function gets executed, with its open close parentheses, okay? So contrary to everything that you may think about, where the this keyword means something to do, like myself or self or anything like that, you're gonna have to set all of those conceptions aside.
[00:02:50] You may have conceptions that the this keyword has something to do with classes, and object orienting, and instances, and all that other stuff. You're gonna have to set all of that completely aside. And you're gonna have to set aside, in general, what the this keyword means in any other language.
[00:03:24] And I'll tell you not only the rules but the order of precedence, in other words, which rule takes precedence, which rule should I ask about first? What you will need to do then, if you ever have another problem with figuring out the this keyword, [COUGH] is to go find the callsite.
[00:03:41] And ask these four rules in order of that call site, and they will definitively tell you what the this keyword will be, that's all you need to know. You don't need to know anything at all about, except for where that function is called, when it's called, how does it get called?
[00:03:57] That's the only thing that matters. Doesn't matter where our function's declared. Doesn't matter whether there's classes, or objects, or anything else involved. The only thing that matters is, what does the callsite look like? And we'll take a look at those four rules. So the first of those four rules that we're gonna look at is actually the fourth rule in terms of order of precedence, and it's the rule that I call the default binding rule.
[00:04:18] So let's examine this code. We've got a function foo up here, lines 1 through 3, and on lines 1 through 3, this function declares that it makes a reference to this keyword. It says this stop bar, so immediately we know that the this keyword needs to reference an object.
[00:04:30] It's not referencing a primitive, a number or a Boolean, and it's always an object. So we're referencing an object that we can look at properties on. So we're expecting that there should be a non empty binding or reference to some object, and we should be able to ask whether or not that object has a bar property on it.
[00:04:48] And if it does, we should be able to get that bar properties value. So when we call foo in the normal sense, I'm gonna call this the plain, undecorated sense of the word for a function call, that looks like line 9. The callsite on line 9, the function stands alone all by itself.
[00:05:05] There's nothing special to it. We can pass parameters if we need to. But it's just a reference to the function, and there's nothing else to that function call. And when that is what the callsite looks like, the default binding rule applies. And I would say that this is also true even with IIFEs.
[00:05:25] So it's when there's just an immediate function right there and it just gets called with a parentheses. So in our IIFE case, where we have a function expression there, same sort of deal. It's the function expression, or in this case, a reference to the variable called foo. But we get that function object right there and then we immediately call it with an open close parentheses.
[00:05:43] That's a normal function call, and in that case, the default binding rule applies. The reason is that none of the other three rules that we're about to learn will apply, so it falls through to the fourth, catch-all rule, the default rule. Now the default rule says this, if you are in strict mode, default of this keyword to the undefined value.
[00:06:03] If you are not in strict mode, default of this keyword to the global object. That's what the default binding rule says. So it gets a default value and it'll either be undefined or it will be the global, and it can't be anything but one of those two values.
[00:06:18] And it's dependent entirely on the strict mode. And by the way, it's not the strict mode of the entire program, but it's the strict mode of the code running inside of the foo function. So if the foo function itself did use strict, then that would be the case.
[00:06:33] It doesn't matter what the outer call code is, it matters only the contents of the function, that's what's gonna define our strict mode here. Okay, so our foo function is being called like that, same thing as if it was an IIFE, it's gonna hit that default rule. Now you remember when I showed you earlier in the spec, I showed you kind of the genesis or the support for that is right there in the spec.
[00:06:56] If you refer back, if you go back to the videos afterwards, you can go back and see I showed you where it had those two points. And one of them said use the this rule, otherwise use the global. So you can see right there where the default rule is coming from.
[00:07:10] Okay, so that's the first of our four rules is the default rule. Let's learn the second of our four rules, we're kind of learning them in reverse order of precedence, by the way, and that's on purpose. The third of our four rules, or the second rule that we're gonna learn, which turns out to be the third of our four rules in precedence, is what I'm gonna call the implicit binding rule.
[00:07:29] So let's take a look at that. What you'll see is, here I've got a couple of [COUGH] objects. I've got an o2 and an o3 object here on line 6 and 7. They both have bar properties on them that have unique values to identify them. But also see that they have references [COUGH] to our same foo function.
[00:08:03] They're just references. So we have, in this case, on line 6, we have two different references to the foo function. We have the global variable foo, that's referencing it, and we have, o2.foo, is referencing it. They are both peer references to the same function object, neither one of them owns more than the other, regardless of where it was declared, they're just references.
[00:08:25] So we just sort of implicitly put a reference to a function on an object, and then, on line 10 you can see, we can say, o2.foo. So we can make a reference to a function via the object property reference. And when we do that, when the callsite looks like o2.foo, in other words, when there is an object property reference at the callsite, the third of those rules in terms of precedence kicks in, which is the implicit binding rule.
[00:08:51] And it says that that object at the callsite, what's called the base object here, or the context object, or the owning or containing object depending on how you think about it. But there's a lot of different ways to explain it. But, that object becomes the this keyword, the this binding.
[00:09:05] So in our case, when we call o2.foo, it's the exact same function being called. But when the callsite is o2.foo, as it is on line 10, then the this keyword will point to o2 and that's why we get bar2. And the exact same thing with o3. Is everybody following so far?
[00:09:22] Two of our four rules already shown just on this one slide. The implicit binding rule has an owning or containing context object at the callsite. The default rule has nothing but just a plain old normal function call.
>> Kyle Simpson: Just to further reinforce the fact that it doesn't matter where a function is declared, nobody owns it more than anybody else.
[00:09:46] In this case I'm doing the exact same thing as in the previous slide. But I put my function initially on o1, and then I made another reference to it on o2. Absolutely no difference in terms of its behaviour. The only thing that matters is what the callsite looks like.
[00:10:00] When I say o1.foo on line 12, I get bar1. When I say o2.foo on line 13, I get bar2. And when I say foo without any kind of thing at the callsite, I get my default binding rule, which gives me bar3.. By the way, if it wasn't obvious, the global object, in this case, in the browser it's the window, in node it's an actual object called the global object.
[00:10:25] But the global object has properties on it which correspond to, that are the same as, any global variables. So, if I have a global variable called bar, there's also a global object property called bar that's, they're not copies of each other they are one and the same. There's a global property and a global variable and they are one and the same.
>> Speaker 1: There's a question from online chat. Is there a place where they can see these rules in writing?
[00:11:08] But I've tried to distill these rules down into human friendly form, the what you need to know form, and that's what I'm presenting here.
>> Kyle Simpson: Okay. So our default rule and our implicit binding rule. Now I wanna take a little bit of a detour for just a moment.
[00:11:27] And I wanna talk about a binding confusion problem that happens with people, because despite, yeah, sorry, was there another question?
>> Speaker 1: Yeah, another one came right after, I'm sorry.
>> Kyle Simpson: No problem.
>> Speaker 1: What happens if o2 doesn't have a bar property? Does it default back to the global bar?
>> Kyle Simpson: Great question. We're not gonna fully be able to answer that actually accurately, but I would say it definitely does not refer back to the global bar.
>> Speaker 1: Does not.
>> Kyle Simpson: It does not. But we'll have to understand the prototype chain before we can actually fully answer that accurately.
[00:11:56] And we'll get to that by the end of the day. So remind them, if you would, that if I don't answer that fully for them by the end of the day to re-ask.