Check out a free preview of the full Deep JavaScript Foundations, v3 course
The "Implicit & Explicit Binding" Lesson is part of the full, Deep JavaScript Foundations, v3 course featured in this preview video. Here's what you'd learn in this lesson:
Kyle differentiates implicit binding from explicit binding by giving several examples of each.
Transcript from the "Implicit & Explicit Binding" Lesson
[00:00:00]
>> Kyle: So let's look at those four different ways to invoke a function. The first of them we'll look at is called implicit binding. You'll notice I have a workshop object with a method on it that is this aware. That should look familiar to you because I called that the name space pattern in another unit of our discussion.
[00:00:17]
We're revisiting that name space pattern here and we're gonna ask how does the this key word behave in that namespace pattern? When I get the ask question invoked, how does it figure out what the this keyword should point at? And the answer is because of the call site.
[00:00:34]
Because of the call site, the this keyword is gonna end up pointing at the object that is used to invoke it, which in this case on line 8 is the workshop object. workshop.ask says invoke ask with the this keyword pointing at workshop. That's what the implicit binding rule says.
[00:00:53]
And by the way, that should be intuitive to you because that's exactly how the this binding works in other languages. So this particular rule is the most common and the most intuitive because it decides the method based upon what function you call it from, I mean, what object you call it from.
[00:01:12]
But it's only one of the four ways, and that's where the extra confusion can come in.
>> Kyle: By the way, the idea of having implicit binding is useful because this is how we share behavior among different contexts. Here I am defining just one ask function, but I'm sharing the ask function across two different objects.
[00:01:40]
workshop1 and workshop2, two separate objects with two separate pieces of data in them. But because on line 7 and line 12 I have a reference to the ask function on it. When I use that reference to invoke the ask function, the implicit binding rule says invoke that one function in a different context each time.
[00:02:00]
So we don't have two ask functions there, just one, but it's invoked in two different contexts. And I could do that not just 2 times, but I could do it 5 times, or 1,000 times, or 1 million times. One function used in lots of different contexts.
>> Kyle: If you think back to how we described the idea of lexical scope, the idea of lexical scope is a very fixed, predictable thing.
[00:02:28]
It's defined at author time, and nothing about the run time can ever change that. And here we have something which is not fixed and predictable, it's entirely dynamic, it's entirely determined at run time. And the trade off here is not accidental, the trade off here is very intentional, that what we really are getting is we're getting the choice between predictable and flexible.
[00:02:55]
Here I benefit from the flexibility of being able to share one function across different contexts. But there are times when that flexibility is a downside and what I would prefer is to have predictability. It's not that one is right and the other's wrong, it's just that these are different tools and they have different benefits.
[00:03:13]
Here we're seeing the flexibility benefit of the this keyword.
>> Kyle: There's another way to invoke functions, we saw this just a couple of slides ago, the .call method. The .call method along with it's cousin, .dot apply method, both of them take, as their first argument, a this keyword.
[00:03:37]
So on line 13, when we say .call and we pass in workshop1, it is saying invoke the ask function with the this context of workshop1. It's very similar to the previous slide, we are still sharing that function, but now we're doing so explicitly rather than implicitly. We're saying wherever this function comes from, invoke it in a particular context which I'm going to specify.
[00:04:06]
>> Kyle: So we can use .call and .apply to explicitly tell JavaScript which context to invoke it in. Now, we're gonna talk about a variation of explicit binding, this is the second of the rules that we're looking at. But this isn't a separate rule, but kind of a sub-rule or a sub-part of this rule, which is an extremely common scenario or phenomenon referred to as losing your this binding.
[00:04:35]
If you've ever worked with a function that you pass around, and all of a sudden, it used to have a this binding and now it doesn't have a this binding, you know what I'm talking about. It's very frustrating when you think of a this keyword as being predictable and then you find out oops, actually, it's not predictable, it's flexible.
[00:04:53]
So variation of explicit binding is called hard binding. Looking at line 8, if I passed in workshop.ask, that method is on the workshop object, but that line 8 is not the call site. You have to imagine in your head, what would the call site look like for the function whenever that timer ran ten milliseconds from now?
[00:05:18]
And that call site would look like cb[], or something like that. It's not going to look like workshop.ask, and because it doesn't look like that, it's not going to invoke ask in a workshop context. Which is we've lost our this binding, we end up getting undefined. Actually just as side note, technically, the set timeout utility is defined by HTML, it's not evoking it just with the default call, it actually explicitly invokes it with a .call in the context of global.
[00:05:55]
So it would actually invoke workshop.ask by saying cb.call window, essentially. Invoking it in the global object context, yes?
>> Speaker 2: Would this be unnecessary if ask were to find us an arrow function?
>> Kyle: Ask here as an arrow function would not solve the problem, but we are gonna talk about arrow functions in just a moment, so we'll come back that.
[00:06:24]
So line 8, we're losing our this binding and it's actually getting rebound to something else, in this case the global object. That's not what we want. So a very common solution to this is line 11, passing a hard bound function. If we pass in a hard bound function using the .bind method, it will take away that whole flexibility thing and force it to only use the this that we've specified on line 11.
[00:06:50]
It says evoke this function, and no matter how you invoke it, always use workshop as it's this context. In other words the .bind method, it doesn't invoke the function, it produces a new function which is bound to a particular specific this context. So you see a trade-off here, right?
[00:07:11]
You see the predictable, flexible this binding, but then you see some scenarios where, [SOUND] it's kind of frustrating that it's flexible. And what I'd really like is for it to be super predictable. There's a tension here. It's not to say that one is right and the other is wrong.
[00:07:29]
But if you were to go to all the trouble to define a bunch of functions on some namespace object, and have this dot in front of every property reference and every method access. And then all of your function calls use the .bind, you would be cutting yourself off at the knees.
[00:07:49]
Because the whole purpose of this system, the whole reason that you pay the tax of putting this dot in front of everything is to get the dynamicism. And then you're going and taking that whole dynamic system and locking it down so that it's completely predictable. At that point, wouldn't you be better served simply writing a module that uses closure and has a fixed, predictable behavior?
[00:08:15]
So how do we deal with this tension? We like using the this keyword, it can be useful to us, but there are times when we need it to not be so flexible. I can't solve that tension for you, but I can just give you a sort of heuristic that I use.
[00:08:30]
If I go to the trouble to write a this aware set of code, and then most of my core sites are using the flexible dynamism, and every once in a while I have to do something like a hard binding. Then I'm getting a lot of benefits out of that system, seems like a reasonable trade-off.
[00:08:48]
On the other hand, if I go to all the trouble to write a this aware system and then everyone or most of my calls sites have to use not bind, that's a clue to me. I'm doing this the hard way. I should switch back and use the predictable lexical closure.
[00:09:03]
In other words, there's a better tool use, there's a better way to use the tool. Use what it's good at. If we want flexible dynamism, use a this keyword, if we want predictability, use closures, use lexical scope.
>> Kyle: So just keep that in mind when you're using the .bind method.
[00:09:24]
Not that it is bad, not that it is evil, not that it is an anti-pattern. But if you find that happening more often than not, you're probably doing things the hard way.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops