I recently wrote about closures and how easier your javascript will be to maintain and how good it will look. Now is the time for me to be a Closure-Grinch.

Closures keep a reference to a variable, not a copy

[source:javascript] // Create a Buy Viagra function function buyViagra() { var pills = 2;

// Create a closure to alert the number of pills
  function alertPills() {
      alert("Number of pills : " + pills);
  }
  
  alertPills();
  
  // Increment the number of pills
  pills += 1;
  
  alertPills();
  

}

buyViagra(); [/source]

Looking at this code, it can be pretty obvious that the alert containing the number of pills will be “2” the first time and “3” the second time. That's because the closures contains the reference to the variable and not a copy.

The common problem with closures and loop

That's a more common problem. We use closures in a loop (for or while) and it always keep the last value of the increment.

[source:javascript] // Functions that will alert a number var alertFunctions = new Array();

for (var iNumber = 0; iNumber < 3; iNumber++) { function alertFunction() { // We use the closures to have access to the variable “iNumber” (from the loop) alert(“Number is ” + iNumber); }

alertFunctions.push(alertFunction);
  

}

// We loop and call each functions for (var i = 0; i < alertFunctions.length; i++) { alertFunctionsi; // Call the function } [/source]

We would expect that three alerts pop having 0, 1, 2. But instead, it alert 3, 3, 3. This is because the iNumber variable was 3 when it got out of the loop.

How to solve the problem

[source:javascript] // Functions that will alert a number var alertFunctions = new Array();

for (var iNumber = 0; iNumber < 3; iNumber++) { // Magic here! var alertFunction = function(x) { return function() { alert(x); }; }(iNumber);

alertFunctions.push(alertFunction);
  

}

// We loop and call each functions for (var i = 0; i < alertFunctions.length; i++) { alertFunctionsi; // Call the function } [/source]

Step #1 var alertFunction = function(x) {

I create a new function that will take a parameter. The parameter will contain a copy of the variable I send to it.

Step #2 return function() { alert(x); };

I return a function that will alert the copied parameter of step #1.

Step #3 }(iNumber);

I call the newly created function (that returns a function).

comments powered by Disqus