Let's introduce closures with an illustration.
There is the global scope. Think of it as the Universe, as if it contains everything.
<Img>
It can contain variables such as a and functions such as F.
<Img>
Functions have their own private space and can use it to store other variables (and functions).
<Img>
If you're at point a, you're inside the global space.
If you're at point b, which is inside the space of the function F, then you have access to the global space and to the F-space.
If you're at point c, which is inside the function N, then you can access the global space, the F-space and the N-space You cannot reach from a to b, because b is invisible outside F. But you can get from c to b if you want, or from N to b.
The interesting thing—the closure—happens when somehow N breaks out of F and ends up in the global space.
<img>
N is in the same global space as a. And since functions remember the environment in which they were defined, N will still have access to the F-space, and hence can access b. This is interesting, because N is where a is and yet N does have access to b, but a doesn't.
N break the chain by making itself global (omitting var) or by having F deliver (or return) it to the global space.
Take a look at this function:
function f() { var b = "b"; return function() { return b; } }
This function contains a variable b, which is local, and therefore inaccessible from the global space
b b is not defined
The return value of f is another function. This new function has access to its private space, to f()'s space and to the global space. So it can see b. Because f() is callable from the global space (it's a global function), you can call it and assign the returned value to another global variable.
As the result—a new global function that has access to f()'s private space.
var n = f(); n(); "b"
The final result of the below example will be the same as the previous example, but the way to achieve it is a little different. f() doesn't return a function, but instead it creates a new global function n() inside its body.
Declare a placeholder n for the global function. This is optional, but it's always good to declare your variables. Then you can define the function f() like below.
var n; function f() { var b = "b"; n = function() { return b; } }
Invoke f().
f();
A new function is defined inside f(). It becomes global since it's missing the var statement. During definition time, n() was inside f(), so it had access to f()'s scope. n() will keep its access to f()'s scope, even though n() becomes part of the global space.
n(); "b"
A closure is created when a function keeps a link to its parent's scope even after the parent has returned.
When you pass an argument to a function it becomes available as a local variable. You can create a function that returns another function, which in turn returns its parent's argument.
function f(arg) { var n = function() { return arg; }; arg++; return n; }
You use the function like this:
var m = f(123); m(); 124
Notice how arg++ was incremented after the function was defined and yet, when called, m() returned the updated value. This demonstrates how the function binds to its scope, not to the current variables and their values found in the scope.
In the below example let us see hard-to-spot bugs while looping a array three times, each time creating a new function that returns the loop sequence number.
The new functions will be added to an array and we'll return the array at the end.
function f() { var a = []; var i; for (i = 0; i & lt; 3; i++) { a[i] = function() { return i; } } return a; }
Run the function, assigning the result to the array a.
var a = f();
Now execute array of three functions. The expected behavior is to see the loop sequence printed out: 0, 1, and 2. Let's try.
a[0]() 3 a[1]() 3 a[2]() 3
These are unexpected values. We created three closures that all point to the same local variable i. Closures don't remember the value, they only link (reference) the i variable and will return its current value. After the loop, i's value is 3. So all the three functions point to the same value.
To implement the correct behavior we need to use three different variables. An elegant solution is to use another closure.
function f() { var a = []; var i; for (i = 0; i & lt; 3; i++) { a[i] = (function(x) { return function() { return x; } })(i); } return a; }
This gives the expected result:
var a = f(); a[0](); 0 a[1](); 1 a[2](); 2
Instead of just creating a function that returns i, we can pass i to another self-executing function. For this function, i becomes the local value x, and x has a different value every time.
Alternatively, you can use a "normal" (as opposed to self-invoking) inner function to achieve the same result. The key is to use the middle function to "localize" the value of i at every iteration.
function f() { function makeClosure(x) { return function() { return x; } } var a = []; var i; for (i = 0; i & lt; 3; i++) { a[i] = makeClosure(i); } return a; }
Using closures we can create getter and setter functions.
We have a variable and if we don't want to expose this variable to any part of the code to alter its value, we can protect this variable inside a function and provide two additional functions, one to get the value and one to set it.
Place both the getter and the setter functions inside the same function that contains the secret variable, so that they share the same scope:
var getValue, setValue; (function() { var secret = 0; getValue = function() { return secret; }; setValue = function(v) { secret = v; }; })()
In the above example, the function that contains everything is a self-invoking anonymous function. It defines setValue() and getValue() as global functions, while the secret variable remains local and inaccessible directly.
getValue() 0 setValue(123) getValue() 123
Using closure we can accomplish Iterator functionality.
We can loop more complicated data structure using closures.
Below is a simple array. Calling next() every time you gives the consecutive value from the input array. It defines a private pointer i that will always point to the next element in the array.
function setup(x) { var i = 0; return function() { return x[i++]; }; }
Calling the setup() function with a data array will create the next() function for you.
var next = setup(['a', 'b', 'c']);
Calling the same function over and over again gives you the next element.
next(); "a" next(); "b" next(); "c"