Closures



A closure is an expression that has free variables. The actual role of a free variable depends on the lexical environment. Programming languages that support closures usually support first-class functions. Creating a function is not equivalent to creating a closure. If free variables of a function have been bound to the lexical environment, it's a so-called closure.

Then what's a free variable? Free variables are not local variables or parameters in a function. Like local variables or parameters, the scope of a free variable is basically defined in a function. It's a bound variable. For example:
js> function doSome() {
  >     var x = 10;
  >     function f(y) {
  >         return x + y;
  >     }
  >     return f;
  > }
js> var foo = doSome();
js> foo(20);

30
js> foo(30);
40
js>

In the above example, the function f creates a closure. If you just look at f:
function f(y) {
    return x + y;
}
It seems that the variable x is not defined. Actually, x is caught from the enclosing function. A closure is a function which closes (or survives) variables of the enclosing function. In the above example, the function f creates a closure because it closes the variable x into the scope of itself. If the closure object, a Function instance, is still alive, the closed variable x keeps alive. It's like that the scope of the variable x is extended.

The doSome function returns a function assigned to foo. After doSome is executed, it seems that the life cycle of the local variable x has ended. The function doSome, however, creates a closure and x is closed in it. The life cycle of x is the same as that of the returned closure function. As above, the result of foo(20) is 10 + 20 because the value of the closed x is 10. Likewise, the result of foo(30) is 10 + 30.

Take care here. What a closure close are variables, not values or references of those variables. The following example proves this concept:
js> function doOther() {
  >     var x = 10;
  >     function f(y) {
  >         return x + y;
  >     }
  >     x = 100;
  >     return f;
  > }
js> var foo = doOther();
js> foo(20);
120
js> foo(30);
130
js>


When a closure is created, it closes the variable x, not the value 10 (stored in x). That's why the results are 100 + 20 and 100 + 30 respectively after doOther updates the value of x. A closure closes a variable so you can update the value of the closed variable.
js> var sum = 0;
js> [1, 2, 3, 4, 5].forEach(function(element) {
  >     sum += element;
  > });
js> sum;
15
js>


You might have questions. If a closure closes a variable and extends the life cycle of it … how about this one?
js> function doOther() {
  >     var x = 10;
  >     function f() {
  >         x--;
  >         return x;
  >     }
  >     return f;
  > }
js> var f1 = doOther();
js> var f2 = doOther();
js> f1();
9
js> f2();
9
js>


In this example, doOther is called twice (or more). The closure f closes x and reduces the value by one. After calling the function f1, x is decreased by one so the result is 9. That's right. But why does the function f2 return 9?

In fact, the results of these two examples are consistent results. Variables closed by a closure are from the enclosing scope. In the above example, when the first time doOther is called, it defines a variable x, specifies it 10 and creates a closure to close it. When doOther is called again, it defines x, specifies it 10 and creates a closure to close it, too. Closures referred by f1 and f2 actually close respective x from different scope. Therefore, after calling f2, the return value is still 9.

The following is a similar example:
js> function doSome(x) {
  >     return function(a) {
  >                 return x + a;
  >            };
  > }
js> var f1 = doSome(100);
js> var f2 = doSome(200);
js> f1(10);
110
js> f2(10);
210
js>


Closures are very useful. For example, a closure can bind a prime table without creating it repetitively.
  • factor.js
function prepareFactor(max) {
     var prime = new Array(max + 1);
     for(var i = 2; i * i <= max; i++) {
         if(prime[i] == undefined) {
             for(var j = 2 * i; j <= max; j++) {
                 if(j % i == 0) {
                     prime[j] = 1;
                 }
             }
         }
     }
     var primes = [];
     for(var i = 2; i <= max; i++) {
         if(prime[i] == undefined) {
             primes.push(i);
         }
     }
     // factor will close primes
     function factor(num) {
         var list = [];
         for(var i = 0; primes[i] * primes[i] <= num;) {
             if(num % primes[i] == 0) {
                 list.push(primes[i]);
                 num /= primes[i];
             }
             else {
                 i++
             }
         }
         list.push(num);
         return list;
     }
     return factor;
}

The variable primes is closed by a closure so the referred object is also available. You can use it as follows:
js> load('factor.js');
js> factor = prepareFactor(1000);
function factor(num) {
    var list = [];
    for (var i = 0; primes[i] * primes[i] <= num; ) {
        if (num % primes[i] == 0) {
            list.push(primes[i]);
            num /= primes[i];
        } else {
            i++;
        }
    }
    list.push(num);
    return list;
}

js> factor(100);
2,2,5,5
js> factor(200);
2,2,2,5,5
js>


A closure can also be used to simulate private accessibility of an object, management of namespace and so on. I'll talk more afterward.