Since someone was curious ;)
Closures require two things:
- Nested Functions - which affects the scope of identifiers
- First-Class Functions - functions can be passed around and returned like data values
Note: I'm using /* */ style comments here, since the syntax highlighter makes a mess of // comments.
This first example demonstrates only nested functions:
/* Nested functions
/ The inner function has access to the local variables of the outer function
/ The inner function is only in scope for the outer function. It can not be seen globally
*/
function a() {
var x = 0;
function b() {
console.log("x =", x);
}
x++;
b(); /* x = 1 */
x++;
b(); /* x = 2 */
}
/* Call a, which will call b, which will output x (from a) */
a();
/* The inner function b is not in scope here */
//b(); // Reference error
This example returns a function object, creating a closure. This exposes the inner function to the outer world in a controlled manner:
/* JavaScript closure
/ Function c returns its inner function d
/ The function d still has access to c's variables even after c has returned
*/
function c() {
var y = 3;
function d() {
return y;
}
return d; /* Return function as value, as opposed to result of calling the function */
}
/* Call c, which will return the function d, which when called returns y (from c) */
var e = c(); /* e = d */
console.log("Function returns:", e()); /* 3 */
/* Can not access d directly. We must be given access by c. */
//d(); // Reference error
This example uses a closure to create a counting object. Each call to the outer function creates a unique context, which is attached to the inner function that is returned:
/* A counter object constructed from a closure */
function generateCounter() {
var count = 0;
function next() {
return count++;
}
return next; /* Return function 'next' along with it's enclosing scope */
}
/* Create a counter object */
var counter1 = generateCounter();
console.log(counter1(), counter1(), counter1()); /* 0 1 2 */
/* Create a new independent counter */
var counter2 = generateCounter();
console.log(counter2(), counter2(), counter2()); /* 0 1 2 */
console.log();
/* Counters proceed independently */
console.log(counter1(), counter1()); /* 3 4 */
console.log(counter2(), counter2()); /* 3 4 */
In this last example, the local variable "count" has limited scope. This makes it similar to a private variable of a class in a language like C++. The function "next" is somewhat like a member function of the class.
In this simple example, only a single member function is visible, which the class-like variables are bound to implicitly. There is no syntactic distinction of "object.memberFunction" here, only "memberFunction".