Check out a free preview of the full Advanced JS Fundamentals to jQuery & Pure DOM Scripting course:
The "Closure Gotchas" Lesson is part of the full, Advanced JS Fundamentals to jQuery & Pure DOM Scripting course featured in this preview video. Here's what you'd learn in this lesson:

Because closures retain access to their call-object and any variables within their call-object’s scope, modifications to the variables can affect all closures and produce undesirable results. Justin demonstrates how wrapping the closure in an immediately invoked function can remedy this problem.

Get Unlimited Access Now

Transcript from the "Closure Gotchas" Lesson

[00:00:00]
>> [MUSIC]

[00:00:04]
>> Justin Meyer: Okay, so back to this. Hopefully, this can be a little bit more understandable now why this was happening. We'll walk through this code the same we just walked through that counter example. So, job's just gonna come to this, it's gonna see a var a equals an object, it's gonna create an object in memory.

[00:00:26] Then it's gonna start this for loop, and the for loop is gonna create a variable i and point it to 0. So, we're gonna kinda start with something like this, in memory. And now we're gonna iterate through the body of the for loop. So, within the body of the for loop, it's gonna create a function in memory, right here.

[00:00:51] And again functions don't know about anything that's going on here. It's not like because this function has an i here, it somehow is going to say, give me the value of i right now. That happens later when this function is actually run. So, it's gonna create a function in memory and it's gonna set i a's, object a's ith property to point to that function.

[00:01:17] So, it's gonna say a and it's 0 with property, points to that function in memory. And now i is going to be incremented to 1, and it's gonna do the same kind of thing. And then i is going to be incremented to 2, and again just a function is gonna be created in memory and a's of 2 is gonna point to that.

[00:01:44]
>> Justin Meyer: Remember, these are all different functions in memory too. Even though you've just defined, you've written function once, it's creating three different functions. And finally, i is gonna be incremented to 3, it's gonna fail the for loop's test and exit the for loop. And then a's of 0 is gonna be called.

[00:02:07] Now whenever a function is called in memory, a call object is created. Again sorry about it being small. This just says a

[0] followed by parentheses. And it's going to run the function body, the function body is going to try to alert i. So, it's gonna look up i.

[00:02:28] And it's gonna start looking up i in this call object here. But that doesn't have an i, so it's gonna walk up again through the parent call object looking for variable i. Find it and then it's gonna alert 3.
>> Justin Meyer: Any questions? Does that make sense now?
>> Justin Meyer: Yeah, kinda, blank stares, okay.

[00:03:00] If there are questions, I'm happy to talk about this ad nauseam because to me, understanding this and especially understanding this and prototypes and stuff like that, is so fundamental to writing good software for jobs, for projects, right. Make sure you're doing things the right way. So, if there is confusion or other things you want to ask in reference, related to this, please ask.

[00:03:29]
>> Justin Meyer: Okay, so the fix for this. So, kind of, understanding closures is the problem we're dealing with right now. Well, the fix for this is adding more closures. Adding more call objects. So, what you can do is wrap this with an immediately invoked function. So, I've wrapped my code, I had before, with another function.

[00:03:57] Because what this is gonna do for us, as we'll see, is it's going to create a individual call object that these inner functions will be referencing and an individual value of j, essentially here, a unique value of j stored in that unique call object. So that this will alert 0, 1, 2 correctly, like we want.

[00:04:23] So, let me do this. So, the other window, we have our a, we have our i, and now we're gonna run in the body of the for loop. Now in the body the for loop, you can see here, we're creating a function. The first thing we're gonna do is create a function in memory.

[00:04:46] So, we create a function in memory. Then the next thing we're gonna do is call that function in memory. And again, whenever you call a function in memory, a call object is created. And that call object is gonna contain any arguments passed to that function. So, here we're passing i, but that's gonna be translated to j.

[00:05:10] And because i is a primitive, j is gonna get its own copy of i. So, that we're gonna create a structure that looks like this.
>> Justin Meyer: And then we are going to run the inside of this outer function here. We're gonna run this function or I guess we are running the function already because we have a call object.

[00:05:40] And we're gonna do what its code says, which is to create another function in memory and then set that as a's of 0. All right, j is gonna be 0, and so is a's of 0, cool. So then, we're gonna just repeat that process. I'm not gonna draw it out for when i is 1.

[00:06:06] And for when i is 2, we're gonna create these things. Okay, now let's see what happens when we call a's of 0. [COUGH] When we call a's of 0,
>> Justin Meyer: Our call object is gonna created, again this is small, so this just says a's of 0 and then call in parenthesis, just like before.

[00:06:33] When we call this function in memory and you call is gonna be created and then it's gonna run that code. Well, where is the thing? Why is the thing, I think something happened. Normally, my presentation shows, it's trying to look up the value of j. Once we run this function, it's gonna run this code in here.

[00:06:54] It's gonna try to look up the value of j and it's not gonna find it because we didn't pass it j. So, it's gonna walk up to find the value of j here that was passed and then alert 0.
>> Justin Meyer: Any other questions about closures? Because we'll be using, we'll be doing something very similar to this is our first exercise immediately following this slide.

[00:07:21] Yeah.
>> Student: Is the j just picking up the boot then or where are you getting the j in there?
>> Justin Meyer: See this, so we're passing i to this function,
>> Student: Okay.
>> Justin Meyer: That function takes as an argument j.
>> Justin Meyer: So, it's like whenever you call, it's just like the sum example,

[00:07:49]
>> Justin Meyer: In this sum example, we're calling sum here with a and b but they become x and y inside the sum. All right, so this is a, Slide Show open, sorry. We're doing the same thing but we're doing it in this kind of weird syntax. It's like we're creating a function but we're not saving it as like a sum variable or anything.

[00:08:16] We're creating it just to call it right away. All right, so we just created a function and then we're calling it with i. But i is gonna be translated to j inside here. Right, so that's, again, what's gonna happen is we create that outer function, we're gonna run that outer function by passing it i, the current value of i, which would be 0.

[00:08:37] But that's gonna create a call object with j or the i translated to j. So, j is gonna point to 0 and that same thing is gonna happen. Cool, any other questions?
>> Justin Meyer: Awesome, so yeah.
>> Student: What, I guess, I'm not sure, can you use void instead of wrapping a function with parentheses?

[00:09:00]
>> Justin Meyer: There is another syntax where you can do like a bang or something to it. I don't, you might be able to I actually, I know, there's different syntaxes that I've seen people use, I always use this to like invoke the function. I don't know if you can use a void or not.

[00:09:17]
>> Student 2: Yeah, you can use, any standard unicode operator, I think. It's like plus, it's been usually to denote something URL related but like a lot of people put like a plus in front of a function cuz that would do the same exact thing and you don't have to wrapping parens but I forget the rules.

[00:09:33] I wanna say something like, yeah, any unicode operator will do it.
>> Student 3: And an alternate way you can do this is just var i equals j, right, without passing it.
>> Justin Meyer: Var,
>> Student 3: Inside the
>> Justin Meyer: Inside the what?
>> Student 3: Inside the anonymous function.
>> Justin Meyer: In here? You can put, instead of passing it, just do var, yeah, you could do that.

[00:09:58] j equals i, yeah, you could do that too. So, to to just illustrate what Mark was just saying, what he meant is, you could just do var j equals i, and then you don't need this. And you're just calling a function, but again your call object is gonna look the exact same.

[00:10:20] It's gonna contain a variable of j that was set to i. This can be, doing it this way, yeah, is fine. They both give the same result. I was about to say something but I realize both suffer from objects instead of primitives that you're kind of passing but that's fine, this works.

[00:10:42] Okay, so just to talk about our recap here. So, this handout, just wanted to touch, kind of go to where we are, and then before we do the exercise. Here's, I guess we do that. We'll recap in a second too but just to show where this is in the exercise.

[00:11:07] This is what happens, everything when you create a function, all the different properties that get set when a function is defined. And then whenever you call a function, this is kind of what a call object gets, what's created inside of a call object. You can see here is the kind of magic references, and everything like that.