This course has been updated! We now recommend you take the Deep JavaScript Foundations, v3 course.
Transcript from the "Explicit Binding" Lesson
[00:00:00]
>> Kyle Simpson: A third way for a function to be called is with the .call or the .apply method. Look at line 9, I'm calling foo, but actually calling it using foo.call. I could have said foo.apply, as well. You'll notice that the first argument passed to both call and apply is used as the this-binding for that function invocation.
[00:00:22] So here, we are explicitly saying, call foo and use obj as its this-context.
>> Kyle Simpson: Which is why we get bar2.
>> Kyle Simpson: That's a third way for a function to be called. So three rules down, default rule, implicit binding rule, explicit binding rule. We're gonna take a slight detour and talk about a variation of explicit binding, which is a problem that we often run into.
[00:00:53] You may have run into this before, it's often referred to informally as losing the this-binding, or having this unbound. What happens is, the function call site is the important part. So let's say you take a function, for example, the one from line 10, and you pass in 02.foo(); as a callback to some other utility.
[00:01:16] And when that utility invokes the function, what is its call site gonna look like? It's gonna override or throw away the 02 this-binding you otherwise normally would have, because it's the call site that matters. So one of the problems that we have is that when we make these this-aware function, we are not in control of how they're going to be invoked.
[00:01:39] And if we're not in control of how they're gonna be invoked, then we cannot predict what their this-keyword is gonna point to. It's called losing your this-binding, everybody following that? So let's imagine this scenario, where I can do something called hard binding. If I wanted to pass in a function, or if I wanted to make a function that, no matter how it was called, it had a predictable this?
[00:02:04] On line 11, I am calling what is referred to as a hard bound function. Look at how foo is defined on line 9. foo is defined, on line 9, to hard-code the .call into it. So that it forcibly says, use obj, no matter how you're called. Which is why, on line 12, if we try to override it, it just silently ignores that, and says, thanks very much, I'm gonna use obj.
[00:02:34] So line 12 would actually still print out bar, not bar2.
>> Kyle Simpson: Now, that pattern of making a function that hard binds it, that explicitly says using .call or .apply? The reason why this is not a rule, but a variation, is because under the covers, it's using a .call or a .apply, which is explicit binding.
[00:02:58] But we don't wanna go making these functions ourselves. That's ugly, to have to make a function like we do on line 9, we could make a utility for that. And it turns out there's a utility built into JavaScript to make these hard bound functions, and it's called .bind.
[00:03:14] On line 7, I make a hard bound version of foo by calling .bind. And the first argument that I pass in, obj, is the this that it will be hard bound to. So now, on line 9, when I call it, it doesn't matter how I call it, It's always gonna use the obj as its this.
[00:03:37]
>> Kyle Simpson: That's called a hard bound function. So any time you've got a function that is this-sensitive, or this aware? And you reference it, and pass it in somewhere, and you're not gonna be in control of the call site? The way to solve that problem is to, instead of passing in the function itself, pass in a hard bound version of the function.
[00:03:58] And then you know it's always going to call, it's always gonna be called using the this that I want it to be called with, okay? Now, I wanna stop for a moment and ask you to analyze, think critically for a moment. Do we see the benefit to gaining some predictability here, with these functions?
[00:04:20] When you say, I want it to always use, I wanna lock it to this specific this, do we see the benefit? It allows us to pass those functions around, and not worry about them losing a this, what's the downside?
>> Speaker 2: You lose flexibility.
>> Kyle Simpson: You lose the flexibility, right?
[00:04:36] Isn't the whole reason for the this keyword to have flexibility? What other system have we already leaned about in this workshop, where we get predictability? [NOISE] Lexical scope, remember that? Lexical scope is all about being fixed at author time, it's all about predictability. The this keyword is all about flexibility, using a function in multiple different contexts.
[00:05:04] So wait a minute, we've just created a pattern which shoots ourself in the foot. Hard binding takes this whole dynamic system, and throws away all the dynamicism, and makes it predictable again. Why would we wanna do that? What I'm getting at here is that there is a tension between flexibility and predictability.
[00:05:24] There's no one right answer here, there's a tension. And because there's a tension, you have to make subjective judgment calls as to which is the appropriate mechanism. So, let me share with you a heuristic that I use to determine, am I doing things the appropriate way, is this best practice?
[00:05:43] Say I architect my code, and I've got all of these this-aware functions defined on some object namespace somewhere. And let's look at all of my call sites, and let's imagine that in all of my call sites, they all look like maybe this one, they all look like o2.foo.
[00:06:03] Okay, great, no big deal, because I'm using the system the way it's appropriately designed. And let's say, every once in a while, I have to make one of these hard bound versions, like we see here on line 7 of this slide. Every once in a while, I have to make a hard bound version, but most of the time, it just says o2.foo.
[00:06:23] In that scenario, I'm taking full advantage of the dynamicism, and every once in a while, inserting back in some predictability. I would say that's a pretty reasonable usage of this mechanism. On the other hand, if I went to all the trouble to put this-dot in front of every single property and method reference, and then I found myself having to do hard binding everywhere?
[00:06:48] I might then step back and say, hmm, maybe I should just switch to lexical scope. Because it appears that the flexibility isn't actually that important in this piece of scope, it appears the predictability is more important.
>> Kyle Simpson: The truth is, different parts of your code will answer that tension differently.
[00:07:08] Some parts of your code, the predictability will be more important, some parts, the flexibility will be more important. You are a better JavaScript developer if you can use both of those techniques appropriately in your code, not one or the other. JavaScript is great, in part, because it has both available to you.
[00:07:26] Using one all the time is not appropriate. I know that's our instinct, just give me the one pattern to rule them all, give me the one ring to rule them all. But what I'm really saying is, you need to learn to use both systems for what they're better at.
[00:07:43] If flexibility is important, if reuse of a function across multiple contexts is important, use this-aware programming. If predictability is more important, the lexical system is better then.