Tuesday, July 31, 2012

Closure in Programming Language

Do you understand closure in programming language?
Some languages have this feature, some doesn't have.But javascript has this feature so as groovy.

Somebody said if you don't need a situation to use closure, you can't understand it fully,lol. So to understand we need get a situation.

#Here is the situation - A classic last value example (Used firefox for this test)

Create 5 buttons on fly and when you click each, it should display "You just clicked Button " + <button number> as shown below

function addButtonsWithHandlers(numOfButtons) {
    var i, button;

    for(i = 0; i < numOfButtons; i++) {
        button = document.createElement("input");
        button.type="button"
        button.value = "Button " + i;
        button.onclick = function() {
            alert("You just clicked Button " + i);
        };

        document.body.appendChild(button);
    }
}

addButtonsWithHandlers(5);

 Now it will alert You just clicked Button 5 every time you click the buttons instead of You just clicked Button 0, You just clicked Button 1, You just clicked Button 2 etc

How do you solve this problem to show the actual button number (like 0,1,2 ...) instead of 5 every-time?

Ans -using Closure. Here is the need for using closure.

Def of closure - An abstraction that represents a function within an environment, a context consisting of the variables that are both bound at a particular time during the execution of the program and that are within the function's scope.

Can you make a solution using the definition above, lol.
  Doesn't make sense above, don't worry. Go through the solution. Closures can be better understood through examples.

Solution as below - 

function addButtonsWithHandlersBad(numOfButtons) {

    var i, button;

    for(i = 0; i < numOfButtons; i++) {

        button = document.createElement("input");

        button.type="button"

        button.value = "Button " + i;

        button.onclick = alertbutton(i);

        document.body.appendChild(button);
    }
}


function alertbutton (i) {
return function () {alert("You just clicked Button " + i);};
}

addButtonsWithHandlersBad(5);
function addButtonsWithHandlers(numOfButtons) {
 

    var i, button;
    for(i = 0; i < numOfButtons; i++) {

        button = document.createElement("input");

        button.type="button"

        button.value = "Button " + i;

        button.onclick = alertbutton(i);

        document.body.appendChild(button);
    }
}

function alertbutton (i) {
return function () {alert("You just clicked Button " + i);};
}


addButtonsWithHandlers(5);


Pay attention to the italic lines in the code above.
So what I did above. I created a function called alertbutton which returns another function. This is a defcato closure, you can say a thumb rule, a function return another function. Then I assign the onclick event of the buttons to that closure.

Another shortcut way of writing the onclick event using closure is as below. This way is called IIFE (Immediately-Invoked Function Expression)


        button.onclick = (function alertbutton (i) {
return function () {alert("You just clicked Button " + i);};
})(i);



That's the actual task you need to do.
What is the underlying theory,
a function return another function makes the returned function closure (in this case, the closure is the anonymous function,i.e, function () {alert("You just clicked Button " + i);})

Another nice example borrowed here is as below,

function localise(greeting) {

    return function(name) { alert(greeting + ‘ ‘ + name };

}

var english = localise(‘Hello’);

var french = localise(‘Bonjour’);

english(‘kartik’);                                 // alert box with “Hello kartik”

french(‘kartik’)                                   // alert box with “Bonjour kartik”

Here, There is a parent function called localise which returns an anonymous inner function. This inner function remembers the variable greeting value even when at runtime the variable does not exist.

Happy Coding!!!
function addButtonsWithHandlersBad(numOfButtons) {
    var i, button;

    for(i = 0; i < numOfButtons; i++) {
        button = document.createElement("input");
        button.type="button"
        button.value = "Button " + i;
        button.onclick = function() {
            alert("You just clicked Button " + i);
        };

        document.body.appendChild(button);
    }
}

addButtonsWithHandlersBad(5);
function addButtonsWithHandlersBad(numOfButtons) {
    var i, button;

    for(i = 0; i < numOfButtons; i++) {
        button = document.createElement("input");
        button.type="button"
        button.value = "Button " + i;
        button.onclick = function() {
            alert("You just clicked Button " + i);
        };

        document.body.appendChild(button);
    }
}

addButtonsWithHandlersBad(5);

1 comment: