Books

Saturday, April 06, 2013

Closures are hard? Not really: A simple introduction to closures in Javascript


The concept of closures exists in various programming languages. Javascript is one of such language, and anybody who spends an ample time with it would sooner or later run into situation where using closures is warranted.

But closures are hard? Not really.

So what are closures? From personal experience, giving a detailed pseudo-academic explanation benefits little in really getting the concept; well, at least for me. I realized that even after understanding it, translating that knowledge into practical usage remained a little fuzzy for a while until I had to use it in real projects once or twice after which I sort of formed a personal mental model for it.

So I won’t give a too much detailed explanation. There are tons of posts and articles out there that already did that. I listed some at the end of this post. What I would quickly outline is how I came to understand it to the extent of practical usage.



Understanding Scope

To get closures you must understand how scope works in Javascript. The scope is what defined the accessibility to a variable or named function. And in Javascript, it is determined by the function in which the variable is defined. That is, Javascript is function scoped. And one interesting thing about this is that the scope can be nested. i.e. If a variable is defined in a function (an outer scope) and inside that function another function (inner scope) is defined. The variables defined in the first outer scope would be accessible inside the second scope. i.e

// global scope
function firstScope() {
  var outer = “I am outer”;

  function secondScope() {
   // I can have access to the scope of firstScope
   var inner;
   console.log(outer);
  }

secondScope();
}

firstScope(); // logs outer since secondscope() is called

// but from global scope, no access to both variable
console.log(outer); //undefined variable
console.log(inner); //undefined variable

You won’t be able to do such a thing in a language like PHP where scope is defined by block of code.

function firstScope() {
    $outer = “I am outer”;

    function secondScope() {
    // I do not have access to $outer
    echo $outer; // this would give an undefined variable error
    }
    secondScope();
}

firstScope();

Now to the interesting part: The magic happens when the inner function which is accessing a variable in the outer function is returned. By this strange situation, all of a sudden the local variable defined in the outer scope gets to survive the execution of the first function. And It becomes available still. This is exactly how a closure is created. ie.

function firstScope() {
    var outer = “I am outer”;
    
     function secondScope() {
    // I can have access to the scope of firstScope
       var inner;
       console.log(outer);
     }

    return secondScope; // secondScope, a function is returned
}

var closure = firstScope();
closure() // console logs the value of the local variable outer

This is something that won’t be possible in a language like C where after the function returns, all local variables are destroyed and are no longer available.

This is how much I would go in explaining Closures. Do check this article for a more detailed explanation.

After you have wrapped your head around scopes and how they create closures in Javascript, next thing are their practicality.

Closures in Real Life 

Closures lend themselves several practical usage. Some of this includes creating Function Templates in Javascript and implementing the Module pattern but before you get to such advanced implementation, there are other scenarios in real life you would find yourself having to use closures; one of such case would be where you need to assign a callback function in a loop.

Let me explain.

Let’s say you need to render a list of buttons which performs the same tasks, but with different parameters. For Instance you want to implement something similar to an email client’s inbox. For each message you want to have a read/open button which when clicked, would open the message. The list of buttons are technically the same: they perform the same function (opening of a message) but on different data. A code to implement this may look like this:

<ul>
  <li><p id=’msgId1’>Message one</p></li>
  <li><p id=’msgId2’>Message two</p></li>
  <li><p id=’msgId3’>Message three</p></li>
  <li><p id=’msgId4’>Message four</p></li>
</ul>

function AttachOPenMsg() {
//let messageList be an array of Id’s for a message
var messageList = [‘msgId1’ , ‘msgId2’ , ‘msgId3’ , ‘msgId4’];

for (var n = 0; n < messageList.length; n++) {
document.getElementById(messageList[n]).addEventListener(‘click’, function(){
alert(“Opening message with Id ” + messageList[n]);
});

}
}

attachOpenMsg();

This makes sense right? Loop through the Id, pick the respective button, and attach the click event that would do the magic of opening the case. The only thing is that this won’t work! Every button you click would always open the last message. This is the kind of situation you use closure for.

So what is the solution?

The definition of the solution would be to create a closure over the looping variable n for the on click event.

That’s sounds nice, but maybe not that clear?

When I first encountered this situation, the first thing I could not understand is why every button have to open the last message? Didn't I just assigned the right value in the loop? Why does it change when it came to clicking?

Let’s unpack it and let see how it works.

Let’s say instead of having a for-loop we had this:

function  attachOpenMsg() {
var n = 0;
document.getElementById(messageList[n]).addEventListener(‘click’, function(){
alert(“Opening message with Id ” + messageList[n]);
});

var n = 1;
document.getElementById(messageList[n]).addEventListener(‘click’, function(){
   alert(“Opening message with Id ” + messageList[n]);
});

var n = 3;
document.getElementById(messageList[n]).addEventListener(‘click’, function(){
   alert(“Opening message with Id ” + messageList[n]);
});

var n = 4;
...
}

attachOpenMsg();

It becomes a little bit clearer why the buttons always use the last value of n in the loop.

In the loop, the value of n keeps changing. And when it gets to the time that the buttons are actually clicked, the value of n that is accessed is the last value before the loops ends. n is referenced by the call back function of the click event, but this is just referencing. If n changes sometimes in the future, the n the callback function references would have changed in value too.

So how does closure help solve this? Well it seems we have to create a closure for the value that is assigned to the call back function such that the changes in the looping n value do not affect it. So you have:

function AttachOPenMsg() {
 //let messageList be an array of Id’s for a message
 var messageList = [‘msgId1’ , ‘msgId2’ , ‘msgId3’ , ‘msgId4’];
 for (var n = 0; n < messageList.length; n++) {
document.getElementById(messageList[n]).addEventListener(‘click’, (function(clsn){
 return function () {
        alert(“Opening message with Id ” + messageList[clsn]);
       }
    })(n);
  });
 }
}

attachOpenMsg();

We using anonymous function here, the n variable is passed into the anonymous function which returns a function that referenced the passed variable n in the form of clsn. The variable n can keep changing but the clsn returned by the closure created by the anonymous function would preserve its value for the click event it was used for.

Instead of anonymous function a named function can be very much used instead:
function openMsg(clsn) {
 return function () {
 alert(“Opening message with Id ” + messageList[clsn]);
 }
}

And then use it in the loop thus

for (var n = 0; n < messageList.length; n++) {
document.getElementById(messageList[n]).addEventListener(‘click’, openMsg(n));
}

Useful links on closures:

http://jibbering.com/faq/notes/closures/
http://stackoverflow.com/questions/111102/how-do-javascript-closures-work
http://helephant.com/2008/10/17/javascript-closures/

3 comments:

  1. Anonymous12:10 AM

    Format the code please :)

    ReplyDelete
  2. Anonymous7:35 PM

    Thank you so much for taking the time to explain Closure and putting together the examples. I have read a lot of writing about Closure, and yours is one of the best.

    ReplyDelete
  3. Great example, I suggest a couple of improvements though: you can use getElementsByTagName instead of creating an array. Also, in the alert you can use this.id, which refers to the current element in the iteration as you sure know. Thanks for your great article!

    ReplyDelete