© 2008, Martin Rinehart
function outer() {
// vars here
// code here
function inner() {
// more vars and code
}
} // end of outer()
You can also achieve a nearly identical result this way:
function outer() {
// vars here
// code here
var inner = function() {
// more vars and code
}
} // end of outer()
I first saw that and said, "Well, looks simple enough, but what does it do that's useful?" Closures are one answer.
function outer([params]) {
// vars declared here
var closure = function([params]) { /* code here */ }
return closure;
}
Someplace else:
var myClosure = outer([args]); // closure returned by outer()
You now have a closure. Your returned inner function can access any vars, parameters and other inner functions (to any depth) declared in the outer function. Sort of.
this and arguments. Other parts, such as the activation object and the execution context are also present, but you cannot access them directly. The important one for us is the execution context.
The execution context contains names and values of, among others, variables, parameters and inner functions. When outer() returns a function it also returns its execution context at the time of the return.
outer() is gone. outer() returns the closure, outer() is done, as is every function which returns. It dies. It has no more execution context. The closure becomes the owner of outer()'s former execution context.
Some authors said (and this was where I got confused) that the closure has access to the variables of the outer function. This is sort of true. Really it has access to the variable's names and values at the moment the closure is created.
makeCompounder() method's execution context to show compound growth.
function closureSample() {
var makeCompounder = function( b, m ) {
var base = b;
var multiplier = m;
var compoundingClosure = function() {
base *= 1 + multiplier;
return base;
}
return compoundingClosure;
} // end of makeCompounder()
var growthFunc = makeCompounder( 100, 0.13 ); // grow 100 at 13%
for ( var i = 0; i < 8; i++ ) {
var val = growthFunc();
var str = ' ' + Math.round( val );
document.write( i + ':' + str + '<br>' );
}
} // end of closureSample()
It's output:
0: 113
1: 128
2: 144
3: 163
4: 184
5: 208
6: 235
7: 266
Note that closureSample() has returned and its execution context is gone (except that it lives on in the closure it returned). It is not executing. (Of course, you could call it again to get another closure with base and multiplier meeting your other needs.)
growthFunc() will continue growing each time you call it, though you have no other access to its variables. Ask for growthFunc.base and you get undefined. You have true private variables owned by a function that is both accessor and mutator.
Java's caretakers have decided to add closures for the 2009 version. Could JavaScript have a more obvious closure syntax, perhaps using a word like "private"?