This course has been updated! We now recommend you take the Deep JavaScript Foundations, v3 course.
Transcript from the "More Closure Examples" Lesson
[00:00:00]
>> [MUSIC]
[00:00:04]
>> Kyle Simpson: What if we use that let keyword? Now, the way it looks is that the let keyword is binding an i to the for loop, but actually, there's a very special behavior in this spec that says it's binding the i, not just to the for loop. It's rebinding that i for each iteration of the for loop.
[00:00:25] So if we started using let i, all of a sudden, it magically creates a brand new i for each iteration that our functions will duly close over. And it'll just work, without needing to insert the IFI. So that's a pretty cool thing that blocks scoping plus loops kind of solves that canonical problem of not having enough scope in each one of our iterations.
[00:00:47] I don't think I have the slide here, but this would be no different than if we had said, for var i=1. And then inside of our iteration loop, we had said something like, let j=i. We would have been creating a j, brand new for each iteration. Like if on line one and a half, I said, let j=i, and then instead of referencing the i's here inside of our function, we reference j.
[00:01:11] We'd obviously be referencing a j that was created for each iteration. So we could do it that way. Turns out there's an extra special behavior that lets in the for header do that automatically for us.
>> Speaker 2: So if you use one of those transpilers to run let on an ES5 and on a long running loop like through 10,000 elements, it's gotta crank out 10,000 exceptions to that catch thing.
[00:01:32] Could that be an extensive performance hit?
>> Speaker 2: Because the let thing is generating a catch block from a thrown exception, so you generate like 10,000 exceptions and catch them 10,000 times. Right?
>> Kyle Simpson: So are you saying if I use let i, regardless of the transpiler, you're saying if I use let i, is that a performance hit, cuz it's creating a whole bunch of i variables?
[00:01:53] Is that what you're asking?
>> Speaker 2: Because when you run it in ES5, the trick was to run it in a catch block, right?
>> Kyle Simpson: Mm-hm.
>> Speaker 2: And to get there you had to throw an exception, right?
>> Kyle Simpson: Mm-hm.
>> Speaker 2: So you guys throw an exception 10,000 times in a loop that loops 10,000 times, right?
[00:02:09]
>> Kyle Simpson: Yeah.
>> Speaker 2: 10,000 stack traces, right?
>> Kyle Simpson: Yes.
>> Speaker 2: I don't know.
>> Kyle Simpson: So if you put this code, as is, into the Google tracer compiler, that's exactly what it would do, is it would put a tricatch inside of the iteration. It would run each one of the 10,000 iterations.
[00:02:25] If, on the other hand, you did something like what I would suggest, where I don't want, let's say, I was in a situation where I didn't need a new i, but I still wanted it to be block bound. Then, I can create an explicit block using let or syntax around the four loop and then it's just one tricatch instead of for each iteration.
[00:02:43] So, yes. The bottom line is that ES6 will have the capability to optimize that binding. Our transpiled ones will take a performance hit, but it's really kind of like, do you want the benefits of block binding, not, do you wanna take a temporary performance hit, cuz eventually, the performance hit will go away.
[00:03:05] But yeah, it's a good point.
>> Kyle Simpson: All right, now given everything I've taught you about closures, I want you to tell me if this particular code is an example of closure. What we have here is we have one of those IFIs running. You can see how I have an IFI running.
[00:03:26] I have a foo that's pointing at this object that gets returned, and this object keeps a reference to this variable inside it. And outside of my function, I'm able to reference something from inside of the function. So by virtue of our definition of closure, is this closure?
>> Speaker 3: No.
[00:03:49]
>> Kyle Simpson: Why not?
>> Speaker 3: It would need to be returned from an inner function, I don't know, it doesn't feel right. [LAUGH].
>> Kyle Simpson: It doesn't feel right?
>> Speaker 3: Yeah.
>> Kyle Simpson: I wish that was a good enough answer for the real world.
>> Speaker 3: I know, right?
>> Kyle Simpson: No boss, I don't know why, but it just doesn't feel right.
[00:04:05] Something's smells wrong. You gotta give me an answer as to why. You gotta defend your position.
>> [INAUDIBLE]
>> Speaker 2: I would take the opposite position.
>> Kyle Simpson: You think it is closure?
>> Speaker 2: Yes.
>> Kyle Simpson: Why is it closure?
>> Speaker 2: It's accessing a variable that doesn't have access to its scope.
[00:04:21]
>> Kyle Simpson: Okay, let's go back to the definition that I gave you for closure. What was the definition that I gave you? There were two characteristics for that definition.
>> Speaker 4: Do you have access to the lexical scope?
>> Kyle Simpson: What was the definition? Can somebody go back and read it to me?
[00:04:35]
>> Speaker 4: Remembers the lexical scope-
>> Kyle Simpson: What remembers its lexical scope.
>> Speaker 4: Function.
>> Kyle Simpson: Well now, function remembers its lexical scope, even when the function is executing outside its lexical scope. Is there a function who is remembering his lexical scope?
>> Speaker 2: No.
>> Speaker 3: No.
>> Kyle Simpson: No. Because we didn't transport a function out.
[00:04:55] This is kind of what you were trying to articulate, there's no interfunction here that's being transported out. We are keeping an object reference around. This code works, you can run this code and it will work. We're keeping an object reference around, but we are not having a function keep a reference to a scope.
[00:05:12] So by definition, this isn't closure. It is object references, but it's not closure. Does that make sense? It's gotta be a function being transported out.