Transcript from the "Closure Introduction" Lesson
>> Kyle Simpson: There are lots of different ways that people over the years have chosen to describe Closure. Lots of different definitions given for it. Closure actually comes to us from lambda calculus. The only thing I know about lambda calculus is that it's called lambda calculus. I don't know anything else about it.
[00:00:15] I took a bunch of cs and a bunch of math classes. Still don't have the foggiest clue what lambda calculus is. All I know is the Wikipedia page says that Closure comes to us from lambda calculus. So I'm not gonna be particularly useful at giving you that hyper-academic definition for this.
[00:00:30] Rather I thought it would be much more appropriate for me to give you a super practical, pragmatic observational definition for Closure. Specifically, this does not match with what an academic, they might say, but well, actually, that stuff doesn't matter. What matters is how do we observe what Closure is, as far as I'm concerned.
[00:00:51] So, this is an observational definition. And by the way if you've been struggling to figure out on those job interviews, how do I answer the question what is Closure, you might wanna use this definition. Closure is when a function remembers its lexical scope even when the function is executed outside of that lexical scope.
>> Kyle Simpson: Closure is the ability of a function to remember and continue to access the variables surrounding it in lexical scopes even if you take that function. Send it elsewhere, pass it elsewhere or return it or something, and it executes in an entirely different scope.
>> Kyle Simpson: This is not a new concept that you've never used in your code.
[00:01:56] When he's shown the Matrix for the first time, he's not seeing a brand new thing. He's seeing something that was always there, and just couldn't recognize it before. And that's what we're about to do is help you recognize where Closure already exists in all your own programs. Here's the foo bar baz kind of example.
[00:02:16] I have a baz function on the inside and that baz function references that bar variable. You'll notice the variable on line 5 references the one from line 2.
>> Kyle Simpson: Now, if I were to call baz right away on line 7, we would describe the ability for it to access that variables plain old normal lexical scope.
[00:02:36] Exactly what we've learned up to this point in the course. But we do something a little different with baz now, we actually pass baz like a call back to some other utility called bam. And on line 12, when we execute baz, can we all agree that baz is now being executed in an entirely different scope than where it was declared?
>> Kyle Simpson: And theoretically, the scope that it was declared in should have gone away and been garbage collected by this point, right? But it didn't. Baz still had access to the bar variable, magically. Well actually not magically, it's Closure. It said that baz, the function baz, closes over the variable bar, because it makes access to a variable in an outer lexical scope.
>> Kyle Simpson: It's as simple as that. When a function references a variable outside of itself, and then that function goes to some other scope and executes and it still has access, that's Closure. That's the most pragmatic, simplified observational definition I've ever been able to come up with for what Closure is.
[00:03:47] Of course, passing a function as a call back like that is not the only way to do so. You can also return functions. That's another way of transporting functions around. Here we have the same thing. An inner function that references bar, we return it and on line 10 even though that looks a little strange to have these two parentheses sets.
[00:04:04] The first parentheses set executes foo, which gets that function back. And then a microsecond later, we have another set of parentheses that execute the returned function.
>> Kyle Simpson: So in that gap of time, right in between those two sets of parentheses on line 10. In that gap, we would think normally, or at least conceptually, that the scope of foo had gone away, cuz foo has finished running.
[00:04:32] And the bar variable should have been garbage collected.
>> Kyle Simpson: But it didn't. Why didn't it?
>> Speaker 2: Cuz we returned the scope.
>> Kyle Simpson: Yeah, but why?
>> Speaker 3: Closure.
>> Kyle Simpson: Closure, because that inner function was closed over that variable which is going to preserve that variable and not allow it to be garbage collected.
[00:04:52] That's what Closure is. The ability of a function to remember and continue to access those variables even when it gets transported and executed elsewhere. Let's look at some more familiar examples. How many of you have ever used a setTimeout before or some sort of timer function? Good chance your function that was your timer hook probably referenced variables outside of itself.
>> Students: Closure.
>> Kyle Simpson: Okay, that function closes over the variable bar. Anybody ever done a click handler before? It closes over the variable bar, same reasoning. You've already been using Closure in all of your programs. All I'm doing is helping you give a definition to it. Now it is important, not just from an academic sake.
[00:05:58] It is important to be able to distinguish what is Closure and what is not because sometimes Closure will work against us. Sometimes Closure will do different things than what we expect. So just like with everything else, it's important to really know it and not just sort of accidentally it, which what we all have been doing.
[00:06:13] We have just been accidentally taking advantage of Closure and now I want you to precisely know what it is and why you use a particular way.
>> Kyle Simpson: Here's two different functions closed over the same variable. It's not like there's a snapshot, they're literally closed over the exact same variable.
[00:06:34] When one of them updates it, the other one is updating the exact same thing.
>> Kyle Simpson: Closure is as many scopes deep as you make it. We've got Closure over different scopes, variables closed over in different scopes, doesn't matter. Closure preserves the access to those variables for as long as those functions exist.
[00:06:55] If you have one scope and there's a thousand different Closures of the variables of that scope. And 999 of those functions go away, they get garbage collected. But there's one function hanging out somewhere in an event handler that had Closure of those variables. Those variables are not gonna get garbage collected.
[00:07:12] As soon as that last function goes away, that last Closure goes away, and now that scope can get garbage collected. If you pay close attention, that means you can accidentally prevent stuff from being garbage collected, if you create a Closure over it. So a few minutes ago, when I said, I try to avoid unintended Closure wherever possible by making my functions at the outer most level.
[00:07:38] The reason is, if I make a function 15 levels deep inside of it, how many scopes is it closed over? Potentially over all 14 of its parent scopes. But if I don't need it all the way deep and I put it all the way at the outside. It's not gonna close over any of those internal ones, so I have less of a chance of it accidentally closing over stuff I don't want it to close over.
>> Speaker 5: It's interesting, so the inner scope can look up the outer scope but not the other way around.
>> Kyle Simpson: Yep, that's lexical scope, that's got nothing to do with Closure, that's just lexical scope. When we have a reference in level 14 to a variable from a level 11, it can go that way.
[00:08:16] But if you have a reference here, and you're trying to reference a variable that isn't declared until an inner scope, here it's just gonna be a reference error. There is no such thing as that variable.