How would you explain JavaScript closures to someone with a knowledge of the concepts they consist of (for example functions, variables and the like), but does not understand closures themselves?
I have seen the Scheme example given on Wikipedia, but unfortunately it did not help.
The secrets for JavaScript functions are the private variables
Every time you call it, local variable "name" is created and given name "Mary". And every time the function exits the variable is lost and the name is forgotten.
As you may guess, because the variables are re-created every time the function is called, and nobody else will know them, there must be a secret place where they are stored. It could be called Chamber of Secrets or stack or local scope but it doesn't really matter. We know they are there, somewhere, hidden in the memory.
But, in JavaScript there is this very special thing that functions which are created inside other functions, can also know the local variables of their parents and keep them as long as they live.
So, as long as we are in the parent -function, it can create one or more child functions which do share the secret variables from the secret place.
But the sad thing is, if the child is also a private variable of its parent function, it would also die when the parent ends, and the secrets would die with them.
So to live, the child has to leave before it's too late
And now, even though Mary is "no longer running", the memory of her is not lost and her child will always remember her name and other secrets they shared during their time together.
So, if you call the child "Alice", she will respond
That's all there is to tell.
You're having a sleep over and you invite Dan. You tell Dan to bring one XBox controller.
Dan invites Paul. Dan asks Paul to bring one controller. How many controllers were brought to the party?
An answer for a six-year-old (assuming he knows what a function is and what a variable is, and what data is):
Functions can return data. One kind of data you can return from a function is another function. When that new function gets returned, all the variables and arguments used in the function that created it don't go away. Instead, that parent function "closes." In other words, nothing can look inside of it and see the variables it used except for the function it returned. That new function has a special ability to look back inside the function that created it and see the data inside of it.
Another really simple way to explain it is in terms of scope:
Any time you create a smaller scope inside of a larger scope, the smaller scope will always be able to see what is in the larger scope.
JavaScript closures for beginners
Closures are not magic
This page explains closures so that a programmer can understand them — using working JavaScript code. It is not for gurus or functional programmers.
Closures are not hard to understand once the core concept is grokked. However, they are impossible to understand by reading any theoretical or academically oriented explanations!
This article is intended for programmers with some programming experience in a mainstream language, and who can read the following JavaScript function:
Two brief summaries
When a function (
foo
) declares other functions (bar and baz), the family of local variables created infoo
is not destroyed when the function exits. The variables merely become invisible to the outside world.foo
can therefore cunningly return the functionsbar
andbaz
, and they can continue to read, write and communicate with each other through this closed-off family of variables ("the closure") that nobody else can meddle with, not even someone who callsfoo
again in future.A closure is one way of supporting first-class functions; it is an expression that can reference variables within its scope (when it was first declared), be assigned to a variable, be passed as an argument to a function, or be returned as a function result.
An example of a closure
The following code returns a reference to a function:
Most JavaScript programmers will understand how a reference to a function is returned to a variable (
say2
) in the above code. If you don't, then you need to look at that before you can learn closures. A programmer using C would think of the function as returning a pointer to a function, and that the variablessay
andsay2
were each a pointer to a function.There is a critical difference between a C pointer to a function and a JavaScript reference to a function. In JavaScript, you can think of a function reference variable as having both a pointer to a function as well as a hidden pointer to a closure.
The above code has a closure because the anonymous function
function() { console.log(text); }
is declared inside another function,sayHello2()
in this example. In JavaScript, if you use thefunction
keyword inside another function, you are creating a closure.In C and most other common languages, after a function returns, all the local variables are no longer accessible because the stack-frame is destroyed.
In JavaScript, if you declare a function within another function, then the local variables of the outer function can remain accessible after returning from it. This is demonstrated above, because we call the function
say2()
after we have returned fromsayHello2()
. Notice that the code that we call references the variabletext
, which was a local variable of the functionsayHello2()
.Looking at the output of
say2.toString()
, we can see that the code refers to the variabletext
. The anonymous function can referencetext
which holds the value'Hello Bob'
because the local variables ofsayHello2()
have been secretly kept alive in a closure.The genius is that in JavaScript a function reference also has a secret reference to the closure it was created in — similar to how delegates are a method pointer plus a secret reference to an object.
More examples
For some reason, closures seem really hard to understand when you read about them, but when you see some examples, it becomes clear how they work (it took me a while). I recommend working through the examples carefully until you understand how they work. If you start using closures without fully understanding how they work, you would soon create some very weird bugs!
Example 3
This example shows that the local variables are not copied — they are kept by reference. It is as though the stack-frame stays alive in memory even after the outer function exits!
Example 4
All three global functions have a common reference to the same closure because they are all declared within a single call to
setupSomeGlobals()
.The three functions have shared access to the same closure — the local variables of
setupSomeGlobals()
when the three functions were defined.Note that in the above example, if you call
setupSomeGlobals()
again, then a new closure (stack-frame!) is created. The oldgLogNumber
,gIncreaseNumber
,gSetNumber
variables are overwritten with new functions that have the new closure. (In JavaScript, whenever you declare a function inside another function, the inside function(s) is/are recreated again each time the outside function is called.)Example 5
This example shows that the closure contains any local variables that were declared inside the outer function before it exited. Note that the variable
alice
is actually declared after the anonymous function. The anonymous function is declared first and when that function is called it can access thealice
variable becausealice
is in the same scope (JavaScript does variable hoisting). AlsosayAlice()()
just directly calls the function reference returned fromsayAlice()
— it is exactly the same as what was done previously but without the temporary variable.Tricky: note the
say
variable is also inside the closure and could be accessed by any other function that might be declared withinsayAlice()
, or it could be accessed recursively within the inside function.Example 6
This one is a real gotcha for many people, so you need to understand it. Be very careful if you are defining a function within a loop: the local variables from the closure may not act as you might first think.
You need to understand the "variable hoisting" feature in Javascript in order to understand this example.
The line
result.push( function() {console.log(item + ' ' + list[i])}
adds a reference to an anonymous function three times to the result array. If you are not so familiar with anonymous functions think of it like:Note that when you run the example,
"item2 undefined"
is logged three times! This is because just like previous examples, there is only one closure for the local variables forbuildList
(which areresult
,i
,list
anditem
). When the anonymous functions are called on the linefnlist[j]()
; they all use the same single closure, and they use the current value fori
anditem
within that one closure (wherei
has a value of3
because the loop had completed, anditem
has a value of'item2'
). Note we are indexing from 0 henceitem
has a value ofitem2
. And the i++ will incrementi
to the value3
.It may be helpful to see what happens when a block-level declaration of the variable
item
is used (via thelet
keyword) instead of a function-scoped variable declaration via thevar
keyword. If that change is made, then each anonymous function in the arrayresult
has its own closure; when the example is run the output is as follows:If the variable
i
is also defined usinglet
instead ofvar
, then the output is:Example 7
In this final example, each call to the main function creates a separate closure.
Summary
If everything seems completely unclear, then the best thing to do is to play with the examples. Reading an explanation is much harder than understanding examples. My explanations of closures and stack-frames, etc. are not technically correct — they are gross simplifications intended to help to understand. Once the basic idea is grokked, you can pick up the details later.
Final points:
function
inside another function, a closure is used.eval()
inside a function, a closure is used. The text youeval
can reference local variables of the function, and withineval
you can even create new local variables by usingeval('var foo = …')
new Function(…)
(the Function constructor) inside a function, it does not create a closure. (The new function cannot reference the local variables of the outer function.)myFunction = Function(myFunction.toString().replace(/Hello/,'Hola'));
), it won't work ifmyFunction
is a closure (of course, you would never even think of doing source code string substitution at runtime, but...).Links
Thanks
If you have just learned closures (here or elsewhere!), then I am interested in any feedback from you about any changes you might suggest that could make this article clearer. Send an email to morrisjohns.com (morris_closure @). Please note that I am not a guru on JavaScript — nor on closures.
Original post by Morris can be found in the Internet Archive.
How I'd explain it to a six-year-old:
You know how grown-ups can own a house, and they call it home? When a mom has a child, the child doesn't really own anything, right? But its parents own a house, so whenever someone asks the child "Where's your home?", he/she can answer "that house!", and point to the house of its parents. A "Closure" is the ability of the child to always (even if abroad) be able to say it has a home, even though it's really the parent's who own the house.
I put together an interactive JavaScript tutorial to explain how closures work. What's a Closure?
Here's one of the examples: