A Graphical Explanation Of Javascript Closures In A jQuery Context
Over the weekend, I was working on my in-depth jQuery presentation for the New York ColdFusion User Group. As part of the presentation, I wanted to discuss the beauty of Javascript "closures" and how jQuery makes tremendous use of them. Javascript closures can be a very hard thing to wrap your head around, especially when you are faced with vague definitions like:
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.
In Javascript, a given context always has access to its parent context. To be honest, the mechanisms behind this visibility are a bit beyond my purview, but I know it has something to do with scope chains (or is it prototype chains - definitely some sort of chain). As such, each method in our demonstration has access not only to its locally defined variables, but also the variables available in its parent context:
|
|
|
||
|
|
|||
|
|
|
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?
These are questions that we can't answer; but, more importantly, these are also questions that the browser's memory management system can't answer (speaking with personification). And, because it doesn't know where these methods are ending up, it can't garbage collect (destroy) the original parent context of the method definitions. That's the power and beauty of the Javascript closure right there - see, even though the methods are being passed away from their original context, due to the scope chains in place, they still have access to their parent context and to all the variables available in their parent context.
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.
Reader Comments
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!
@Aaron,
Oh heck yeah!
You're a star!!! That's a really good explanation!!!!!!!! Thanks for that Ben
What makes most of this possible is that JavaScript is "lexically scoped." This means that something is in the scope in which it was defined--not where it ends up. Wherever I wrote the function, it is in (and stays in) that scope.
Lexical scoping and lambda (anonymous) functions combined with JavaScript's awesome chaining capabilities also make for some brilliant ways to namespace your projects and emulate class-like method/property access-control (i.e. public and private). It is what makes jQuery possible!
Once you wrap your head around these concepts, JavaScript becomes a sexy and extremely flexible and powerful language. Yes, I called a programming language sexy!
...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.
@Jim,
I have seen one or two examples of public/private emulation with Javascript. At the time, I didn't understand enough Javascript to see how that was working. Maybe it would be different now.
Yeah, it is sexy stuff!
A very thorough explanation of Javascript closures can be found here (take a deep breath) :
http://www.jibbering.com/faq/faq_notes/closures.html
> 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...
@Zorg,
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.
@Ben
> 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 :)
@Zorg,
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.
Too complicated.
Where did you learn this? Do you know of any good resource or book for learning functional JavaScript from ground-up?
@dl
JavaScript: The Good Parts
Unearthing the Excellence in JavaScript
By Douglas Crockford
This is good to learn and many thanks to Douglas.
@FM,
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!
@Andrew,
That's awesome!! Glad you felt it was worthy :)
+1 Douglas Crockford : this is the best book about the functional core of JS. (don't miss his videos 7 on Javascript + 3 on DOM).
for the OO model of Javascript see Liberman paper on prototype-based inheritance and see the papers on Self by Ungar.
all this is freely available online
@Zorg,
Do you have a link to the Ungar paper?
http://selflanguage.org/documentation/published/index.html
Self the power of simplicity, is a good place to start
http://web.media.mit.edu/~lieber/Lieberary/OOP/Delegation/Delegation.html
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... :)
@Joel, @Julian,
Glad you guys are liking it.
Images aren't appearing!
@Richard,
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!!!
Thanks Ben
vimal
Germany
man, this was clear. As I m getting more into JavaScript seriously, I realize that I can see the big picture more easily and It makes me really damn happy.I thought that closures were more complicated than that.Man, javascript is awesome. It really is the punk rock language!
Ben,
Loved this.... I recommended it to several folks who (like me) tend to see closures as just out of reach mentally :)
-Mark
Great post Ben! This is helping me to understand JavaScript more. Much appreciated.
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.
If variables in the outer context change, these changes affect the inner anonymous functions as well. That means: if you change the outer variable at some later time, the inner function sees the changed value! Not the value the variable had when the inner functions was created. For me, that's not a closure. JavaScript do not have real closures at all in my opinion due to that!
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.
I am used to Perl and closures in Perl do not have this flaw. All lexical variables from the outer scope are bound (with their actual value) into the inner function. The inner function may change the variable. All other instances of the same inner function do not see this change! In JavaScript this happens.
To get a "real" closure in JavaScript you have to wrap the critical code, which likes to get the outer variables enclosed with their state on function creation time, you have to wrap around another function, which gets these parameters passed, and call it immediately, passing these parameters. That's what Prototypes bind() method is doing effectively.
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 ;)
I am new to Javascript and have read lots of the scary explanations of a Closure. This is the best and the most easy-to-follow explanation that I have read. Many thanks for this.
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?