A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).
I mean, come on, what the heck does that mean? I know a bit about closures and that definition doesn't make sense to me. Like I said, closures can be a hard thing to really understand. As such, I wanted to try and explain them [closures] with the help of some graphics because, as they say, a picture is worth a thousand words.
First, let's look a simple jQuery demo:
| || || |
| || |
| || || |
In this code, we are adding click event handlers to all of the links in the document. These click event handlers, when triggered, will alert the index of the given link in the context of the entire set of document links. Of course, the intent of the code is secondary to the demonstration. What's of primary importance here is structure of the code. Take a look at the functions that are being defined:
| || || |
| || |
| || || |
Notice that we are defining three anonymous methods in this demo. Each of these methods is defined within a parent context. The outer-most method is defined in the context of the window (theoretically based on the visible code); the middle method is defined in the context of the outer-most method; and the inner-most method is defined in the context of the middle method.
| || || |
| || |
| || || |
Notice that in the inner-most method, it has to move up one scope in the parent chain to find "intLinkIndex," but it has to move up two scopes in the chain to find the "jLinks" variable. While it might not be obvious, the two-parent-context-jump is following the same exact rules - first, the inner-most method looks for jLinks in its own context. Since it's not a local variable, it can't find it. Then, it asks its parent context (the middle method) for the variable. The middle method checks its local scope and can't find it, so it passes this request up to its parent context, the outer-most method. And, because each context has access to its parent context, this variable request is easily passed up the context chain.
Ok, so far so good; now, let's really get into closures. Keeping this whole parent context concept in mind, take a look at where these defined methods are ending up:
| || || |
| || |
| || || |
As we are defining these anonymous methods, we are using the each() method and the click() method to pass these functions away from their parent context. Where are they going? We don't know - they're being passing into another context altogether. Sure, from the demo code, it looks like they are getting passed to jLinks and jThis respectively; but, the fact is, once these method references are passed into those foreign contexts, we can't say with certainty how they are being used. Are they transient? Are they being cached somehow in the window object for the entire life of the page?
So, the real message to take away here is that when you pass a method reference out of the context in which it was defined, the method still has access to its parent context. And, once you understand and embrace this, it can be leveraged in some really cool ways (as seen in this jQuery example). This is not the most in-depth explanation of closures, but hopefully these graphics have helped you to better understand the closure mechanism.
Ben: Good explanation -- one of the best explanations I've seen.
There is also a great video on Advaned JS by Douglas Crockford that goes into details on how this works behind the scenes. Check it out.. its available in the YUI theater: http://video.yahoo.com/watch/111585/1027823
I second Brian's comment. As I was reading through the post I was thinking I'd have to find the same video.
Pretty much all of the Crockford videos on Yahoo! are worth your time. Some of them get mind-bendingly complex, but they'll really open your eyes.
Having said all of that, I'll also say that your post is an excellent explanation of a very confusing concept. Very nicely done.
Thanks guys. I'll have to check out the YUI videos. I think I went there once and was just overwhelmed with the amount of content :) Time to get over that fear!
Looking forward to the presentation next week!
Oh heck yeah!
You're a star!!! That's a really good explanation!!!!!!!! Thanks for that Ben
...continued from my previous comment...
I forgot to add that the chaining capabilities allow for "self executing" lambdas which is one of the coolest namespacing tools available.
Great explanation, love the images. Nice to see such a pragmatic explanation, without to much detail to confuse the topic.
Yeah, it is sexy stuff!
> A "closure" is an expression (typically a function) that can have free
> variables together with an environment that binds those variables (that
> "closes" the expression).
> I mean, come on, what the heck does that mean? I know a bit about
> closures and that definition doesn't make sense to me.
too bad, because it's exactly what a closure is !
Free variables are identifiers in the function body that are not parameters.
An environment is a list of names and their associated values, used to evaluate expressions.
So there you have it : a closure is an expression that can look up an environment for the values of its free variables or , to use your own terms, an expression that has "access to their parent context"
> As we are defining these anonymous methods, we are using the each()
> method and the click() method to pass these functions away from their
> parent context. Where are they going? We don't know - they're being
> passing into another context altogether. Sure, from the demo code, it
> looks like they are getting passed to jLinks and jThis respectively; but,
> the fact is, once these method references are passed into those foreign
> contexts, we can't say with certainty how they are being used. Are
> they transient? Are they being cached somehow in the window object
> for the entire life of the page? These are questions that we can't answer...
they can be answered though :
in the case of jThis, the anonymous function is registered as a handler for the onclick event (think about it as being referenced by the <a> element itself)
in the case of jLinks, the anonymous function is executed for each (index, obj) in jLinks, ... maybe that's what you call transient ? In any case once that block has executed, that function is gone...
That is a great link and is, in fact, where I got the original definition for closures.
As far as where the functions go, I am sorry if I did not communicate well; I understand that yes, we can look into the Click event wiring and actually see where it goes; what I mean to get across in a more abstract way is that when a method is passed out of its parent context, we should not assume anything about where it goes or how long it lives. And, in doing so, we can start to become comfortable with the idea that the variables in its parent scope must be kept around in case the method reference is ever executed.
I wanted to get people comfortable with the idea of closures at a high level, not so much with the specifics of the behind the scenes.
> I wanted to get people comfortable with the idea of closures at a high
> level, not so much with the specifics of the behind the scenes.
Sorry, I missed that :)
Nothing to be sorry about at all my friend. Closures are a really complex concept for people to get. The more insight that people such as yourself can offer, the better off we all are going to be.
By Douglas Crockford
This is good to learn and many thanks to Douglas.
I've heard that that is a very good book.
I've translated your article into Russian. Thought you don't mind.
All the backlinks are proveded. Here is the full version: http://interpretor.ru/js_closures/
Thank you for the great article!
That's awesome!! Glad you felt it was worthy :)
all this is freely available online
Do you have a link to the Ungar paper?
Self the power of simplicity, is a good place to start
for the Lieberman paper
This was great to understand. Thank you
I think jQuery convert all the $("a") into objects.
and then jLinks.each assign jThis.click method to each of the "a" objects.
Thank you, that's the best explanation I have seen.
Thanks for this, nice bit of graphical explanation but now I need to know more... :)
Glad you guys are liking it.
Images aren't appearing!
My server has been having some issues lately. Try hitting this blog post again and it should work. Sorry about the dips in performance.
I especially liked your site posts, and so on through all of them beautiful
I loved this explanation of closure with scope-chaining. Clearest ever article on closure!!!
Loved this.... I recommended it to several folks who (like me) tend to see closures as just out of reach mentally :)
Wonder full effort Ben... really opens a new dimension of js variables. Thanks Alot
Thanks for this article, but I fear you missed an important point.
Your code just appears to do what you think it should do, because your jLinks variable isn't changed during looping over all the 'a' elements. If it would change, all inner functions would see the last value this variable had. That's mostly not what the developer expects.
Please refer to http://pastebin.com/NhnXTP5p as an example to show the difference.
You see all links in the testbed1 div share the same i variable. Even copying this variable to another lexically scoped variable inside the loop doesn't help.
The links in testbed2 do not suffer from this, since the click() callback is put inside a wrapper function. Each link has its own "copy" of the variable. The callback changes this variable and you see that the state is maintained for each link separately.
I hope this helps clarifying this topic. I know your posting is 3 years old, but since it shows up inside the top 10 of a Google search for "jQuery Closure" I think it's worth add some stuff to it ;)
Huh, this explanation made me wonder why closures are so confusing in the first place... :P made it seem pretty elementary to me.
One thing though: so when people refer to "closures" as a noun -- e.g. "create a closure" --- they basically mean create an anonymous function within a method like .each() or .click() which take themselves to a new mystical context?