Simply Closures – Part II -> The Meat
Scope Chains
A function can see variables at it’s own level and all it’s ancestors.
ie. see the following (n.b. none of the inner functions are closures)
$(document).ready(function() {
scopeChains();
});
var _global = true;
function scopeChains() {
var _inner1 = true;
logVars('in scopeChains', _inner1); // _inner2 and _inner3 are out of scope
function inner1() {
var _inner2 = true;
logVars('in inner1', _inner1, _inner2); // _inner3 is out of scope
function inner2() {
var _inner3 = true;
logVars('in inner2', _inner1, _inner2, _inner3);
}
inner2();
}
inner1();
}
function logVars(sFunctionName, inner1Var, inner2Var, inner3Var) {
logLine('***** ' + sFunctionName + ' *****');
logLine('_global = ' + _global);
logLine('_inner1 = ' + (typeof (inner1Var) == 'undefined' ? 'undefined' : inner1Var));
logLine('_inner2 = ' + (typeof (inner2Var) == 'undefined' ? 'undefined' : inner2Var));
logLine('_inner3 = ' + (typeof (inner3Var) == 'undefined' ? 'undefined' : inner3Var));
logLine('*****************************');
}
function logLine(sContent) {
$('#txtArea').val($('#txtArea').val()
+ sContent + '\r\n');
}
Outputted
***** in scopeChains *****
_global = true
_inner1 = true
_inner2 = undefined
_inner3 = undefined
*****************************
***** in inner1 *****
_global = true
_inner1 = true
_inner2 = true
_inner3 = undefined
*****************************
***** in inner2 *****
_global = true
_inner1 = true
_inner2 = true
_inner3 = true
*****************************
Breaking the Chain
How does an inner function break the chain?
-
By making itself global (omitting var)
var n; function f() { var b = 'b'; n = function() { return b; }; } // note, what about if we omit 'n=' -
By having F return it to global space
function f() { var b = 'b'; return function() { return b; }; }
The concept of captured Variables
The root of the chain is what holds all instances.
I’m going to call it an instance stream, each broken chain has it’s own set of instances.
function closureFunction(theVal) {
return function() {
// chain is broken, therefore
// theVal is from a new instance stream
log(theVal++);
}
};
$(document).ready(function() {
var arrFunctions = [];
arrFunctions[0] = closureFunction(10);
arrFunctions[1] = closureFunction(20);
arrFunctions[2] = closureFunction(30);
for (i = 0; i < 3; i++) {
log('index = ' + i.toString());
arrFunctions[i]();
arrFunctions[i]();
}
});
function log(sContent) {
$('#txtArea').val($('#txtArea').val()
+ sContent + '\r\n');
}
Outputted:
index = 0
10
11
index = 1
20
21
index = 2
30
31
To get parameter into closure space
an argument to outer function essentially becomes a local variable,
thereby we can pass an argument which will become it's own instance.
function f(arg) {
var n = function() {
return arg++;
};
return n;
}
ie the arg is basically like a local like so:
function f() {
var arg = 2;
var n = function() {
return arg++;
};
return n;
}
so we have a parameter, which becomes it's own instance in the closure,
$(document).ready(function() {
var arrFunctions = [];
var iCounter = 0;
for (var i = 0; i < 5; i++) {
iCounter = i * 10;
arrFunctions[i] = (function(theCounter) {
return function() {
log(theCounter);
theCounter++;
}
})(iCounter);
}
for (i = 0; i < 5; i++) {
log('index = ' + i.toString());
arrFunctions[i]();
arrFunctions[i]();
}
});
function log(sContent) {
$('#txtArea').val($('#txtArea').val() + sContent + '\r\n');
}
outputs:
index = 0
0
1
index = 1
10
11
index = 2
20
21
index = 3
30
31
index = 4
40
41
very useful for say ajax.
imagine that _airlineDom, _flightNumDom, _opSuffixDom are input boxes.
e.g.
doAjaxPost('updateAirlineName', _airline, true,
(function() {
return function(data) {
successHandler.call(this, data);
_airlineDom.val('');
_flightNumDom.val('');
_opSuffixDom.val('');
}
})(_airlineDom, _flightNumDom, _opSuffixDom),
failureHandler);


