Closure and Scope

The term closure refers to a function which references variables outside of its scope; the function is “closed over” those variables.

I’ll give an example of misusing closure in JavaScript and C#, then compare the solutions.  This example is going to attempt the trivial task of outputting the digits 0 through 9.

JavaScript
for (x = 0; x < 10; x++) {
    setTimeout(function () {
       console.log(x);
    }, 1);
}
C#
for (int x = 0; x < 10; x++) {
    setTimeout(() => 
		Console.WriteLine(x)
	, 1);
}

This assumes that a setTimeout method has been created for C#, just for the purposes of demonstrating this.  In reality, you’ll run into this when you’re wiring up events with lambdas, iterating over LINQ queries, or using methods like List<T>’s ForEach.

The problem in these two examples is that the function passed to setTimeout is closed over the variable x; that is, we’re not referencing the value of x in the function, but the variable itself (similarly to a ref parameter in a C# method).  By the time the function runs, x is 10, so the output to the console is actually 10 being output 10 times (see for yourself).

To fix this problem, we need to pass a new variable which always hold the correct value to each function.  In C# this is pretty easy, because the for block provides scope.

for (int x = 0; x < 10; x++) {
   var closedX = x;
   setTimeout(() =>
        Console.WriteLine(closedX)
    , 1);
}

However, in JavaScript, only functions provide scope.  If we tried this same technique in JavaScript, closedX would be the same variable in each run of the for loop (even though we’re using var to “declare” it).  We need a new function to provide the scope to create separate variables for each run.

for (x = 0; x < 10; x++) {
    setTimeout((function (closedX) {
       return function () {
           console.log(closedX);
        }
   }(x)), 1);
}

Here, we create a function which has one parameter, closedX, then immediately call it, passing in x.  The parameter is a new variable for each run of the for loop because the function give it a scope, so it gives us the desired outcome.

Feel free to leave any questions in the comments, play with the example above on jsFiddle, and enjoy JavaScript to its fullest.

4 Comments

  • Nice one!

    I prefer to write closures in a loop like this :

    for(var x = 0; x < 10; x++) {
    (function(x) {
    setTimeout(function() {
    console.log(x);
    }, 1);
    }(x));
    }

    Essentially, you just wrap the body of your loop in an IIFE.

  • That's a great point, rumpl. You can wrap the entire setTimeout call, or just the function inside it. In reality, I'd probably do it that way, too; it seemed cleaner to move it to its smallest scope for the example, but I think that's easier to read. That also points out that you get to reuse the variable name (which you can't do in the C# example), which is usually simpler to read.

  • Yeah, I find it easier to read too.

    Now. I just read the documentation of setTimeout so what I am about to say has nothing to do with what you are trying to acheive (show the power/use of closures), but I find it pretty cool:

    setTimeout can in fact be called in two ways :
    1. the old way: setTimeout('some code in a string', delay);
    2. the better way: setTimeout(someFunction, delay, [param1, param2, ...]);

    So, basically, your example can be rewritten like so :

    for (x = 0; x < 10; x++) {
    setTimeout(function (x /* or closedX */) {
    console.log(x /* or closedX */);
    }, 1, x);
    }

    Wicked eh? :)

  • @rumpl

    Whoa! Being able to pass in parameters via the setTimeout call is awesome! However, just looked at MDC, and it notes that IE doesn't support this... Consider me disappointed.

Comments have been disabled for this content.