Uncategorized

Javascript, closures and scoping

On Thursday this week I went to the Kitchener/Waterloo Perl Mongers to give a talk about Node.js. Those guys are old friends of mine, and had heard about the work I’d been doing and were curious to learn more.

One thing that was clear during the talk is that there’s little love for Javascript. That’s partly because it is flawed, and partly just a perspective thing.

An example I gave which caused particular vitriol was the issue of there being no lexical scoping, just (module) global and function scoping. This means that creating a closure around a variable is a bit hard, which is a major sin for a language that is entirely based around callbacks. The example I gave was trying to be very simplistic:

for (i=0; i<10; i++) {
  var j=i;
  setTimeout(function () { console.log(j) }, 1000);
}

Which doesn’t work properly because the “var j=i” line creates a variable at function (or global) scope, not lexically inside the for loop, so you have to turn it into this:

for (i=0; i<10; i++) {
    setTimeout((function (j) {
        return function () {
            console.log(j)
        }
    })(i), 1000);
}

Which looks really ugly, because you have to call a function (to get the “function variable scope”) passing in the value, and return the function/callback that is to be called.

The KW.pm guys called me out that this is a bit of a convoluted example, but I realised there’s a great example of where this happens in real life in Node.js. Say you’re looping over a list of users, fetching preferences from a database:

for (var i=0,l=users.length; i < l; i++) {
    var user = users[i];
    user.get_preferences(function (pref) {
        console.log("User: " + user.name + " preference is: " + pref);
    });
}

And there we have a perfectly failing example, because by the time the callback is executed, “user” will be the last user in the list, even inside the closure.

Roll on Javascript’s “let” keyword, which will create a lexical variable. I hope that is available in Node 0.6.

Standard

2 thoughts on “Javascript, closures and scoping

  1. It’s annoying, and I usually avoid the for loop if I can. For example, you could rewrite that last one as

    users.forEach(function(user){
    user.get_preferences(function (pref) {
    console.log(“User: ” + user.name + ” preference is: ” + pref);
    });
    });

    BTW you can also use bind if you’re working server-side:

    for (i=0; i<10; i++) {
    (function (i) {
    // do something with i
    }).bind(this,i);
    }

    for (i=0; i<10; i++) {
    setTimeout((function (j) { console.log(j) }).bind(this,i), 1000);
    }

    Still hideous though. Everyone gets bit by that damn for loop, rite of fucking passage.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s