Categories:

More closure examples

For some reason closures seem really hard to understand when you read about them, but when you see some examples you can click to how they work (it took me a while). I recommend working through the examples carefully until you understand how they work. If you start using closures without fully understanding how they work, you would soon create some very weird bugs!

Example 3

This example shows that the local variables are not copied - they are kept by reference. It is kind of like keeping a stack-frame in memory when the outer function exits!

function say667() {
	// Local variable that ends up within closure
	var num = 666;
	var sayAlert = function() { alert(num); }
	num++;
	return sayAlert;
}


Example 4

All three global functions have a common reference to the same closure because they are all declared within a single call to setupSomeGlobals().

function setupSomeGlobals() {
	// Local variable that ends up within closure
	var num = 666;
	// Store some references to functions as global variables
	gAlertNumber = function() { alert(num); }
	gIncreaseNumber = function() { num++; }
	gSetNumber = function(x) { num = x; }
}


 

The three functions have shared access to the same closure - the local variables of setupSomeGlobals() when the three functions were defined.

Note that in the above example, if you click setupSomeGlobals() again, then a new closure (stack-frame!) is created. The old gAlertNumber, gIncreaseNumber, gSetNumber variables are overwritten with new functions that have the new closure. (In JavaScript, whenever you declare a function inside another function, the inside function(s) is/are recreated again each time the outside function is called.)

Example 5

This one is a real gotcha for many people, so you need to understand it. Be very careful if you are defining a function within a loop: the local variables from the closure do not act as you might first think.

function buildList(list) {
	var result = [];
	for (var i = 0; i < list.length; i++) {
		var item = 'item' + list[i];
		result.push( function() {alert(item + ' ' + list[i])} );
	}
	return result;
}

function testList() {
	var fnlist = buildList([1,2,3]);
	// using j only to help prevent confusion - could use i
	for (var j = 0; j < fnlist.length; j++) {
		fnlist[j]();
	}
}

The line result.push( function() {alert(item + ' ' + list[i])} adds a reference to an anonymous function three times to the result array. If you are not so familiar with anonymous functions think of it like:

pointer = function() {alert(item + ' ' + list[i])};
result.push(pointer);

Note that when you run the example, "item3 undefined" is alerted three times! This is because just like previous examples, there is only one closure for the local variables for buildList. When the anonymous functions are called on the line fnlist[j](); they all use the same single closure, and they use the current value for i and item within that one closure (where i has a value of 3 because the loop had completed, and item has a value of 'item3').

Example 6

This example shows that the closure contains any local variables that were declared inside the outer function before it exited. Note that the variable alice is actually declared after the anonymous function. The anonymous function is declared first: and when that function is called it can access the alice variable because alice is in the closure. Also sayAlice()(); just directly calls the function reference returned from sayAlice() - it is exactly the same as what was done previously, but without the temp variable.

function sayAlice() {
	var sayAlert = function() { alert(alice); }
	// Local variable that ends up within closure
	var alice = 'Hello Alice';
	return sayAlert;
} 


Tricky: note also that the sayAlert variable is also inside the closure, and could be accessed by any other function that might be declared within sayAlice() or it could be accessed recursively within the inside function.

Example 7

This final example shows that each call creates a separate closure for the local variables. There is not a single closure per function declaration. There is a closure for each call to a function.

 function newClosure(someNum, someRef) {
	// Local variables that end up within closure
	var num = someNum;
	var anArray = [1,2,3];
	var ref = someRef;
	return function(x) {
		num += x;
		anArray.push(num);
		alert('num: ' + num + 
			'\nanArray ' + anArray.toString() + 
			'\nref.someVar ' + ref.someVar);
	}
}