function - How do JavaScript closures work?
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 href="http://en.wikipedia.org/wiki/Scheme_%28programming_language%29"
rel="noreferrer">the Scheme example given on Wikipedia, but unfortunately
it did not help.
itemprop="text">
Submitted by
Morris on Tue, 2006-02-21 10:19. Community-edited
since.
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:
class="snippet" data-lang="js" data-hide="false" data-console="true"
data-babel="false">
class="snippet-code-js lang-js prettyprint-override">
function
sayHello(name) {
var text = 'Hello ' + name;
var say = function()
{ console.log(text); }
say();
}
sayHello('Joe');
Two
brief
summaries
When a
function (foo
) declares other functions (bar and baz), the
family of local variables created in foo
is not
destroyed when the function exits. The variables merely become invisible to
the outside world. foo
can therefore cunningly return the
functions bar
and baz
, 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
calls foo
again in
future.
A closure is one way of
supporting rel="noreferrer">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:
data-lang="js" data-hide="false" data-console="true"
data-babel="false">
class="snippet-code-js lang-js prettyprint-override">
function
sayHello2(name) {
var text = 'Hello ' + name; // Local variable
var say = function() { console.log(text); }
return
say;
}
var say2 = sayHello2('Bob');
say2(); // logs "Hello
Bob"
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 variables
say
and say2
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 the
function
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 from
sayHello2()
. Notice that the code that we call references the
variable text
, which was a local variable
of the function
sayHello2()
.
function()
{ console.log(text); } // Output of
say2.toString();
Looking
at the output of say2.toString()
, we can see that the code
refers to the variable text
. The anonymous function can
reference text
which holds the value 'Hello
Bob'
because the local variables of sayHello2()
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!
class="snippet" data-lang="js" data-hide="false" data-console="true"
data-babel="false">
class="snippet-code-js lang-js prettyprint-override">
function say667()
{
// Local variable that ends up within closure
var num =
42;
var say = function() { console.log(num); }
num++;
return say;
}
var sayNumber = say667();
sayNumber(); //
logs
43
No comments:
Post a Comment