Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does a function in a loop (which returns another function) work? [duplicate]

Tags:

I've been trying to assign a function to onclick event of a dynamically created "a" tag in JavaScript. All of the tags are created in a loop as follows:

for ( var i = 0; i < 4; i++ ) {   var a = document.createElement( "a" );   a.onclick = function( ) { alert( i ) };   document.getElementById( "foo" ).appendChild( a ); } 

The alerted value for all four links is always "4". Pretty obvious. When googling I came across a post that shows the following code snippet:

a.onclick = (function(p, d) { return function(){ show_photo(p, d) } })(path, description); 

I managed to tweak it for my needs and got the alert( i ) thing to work correctly but I'll appreciate if someone could explain exactly what the above code does.

like image 862
Salman A Avatar asked Oct 12 '09 05:10

Salman A


People also ask

What is on() function in JavaScript?

The on() method attaches one or more event handlers for the selected elements and child elements. As of jQuery version 1.7, the on() method is the new replacement for the bind(), live() and delegate() methods.

Can I and two for loops?

Yes you can do a for loop like that, but you have one and just one condition for check. If you can make it check just a one condition for all of your variables for example an And (&&) conditional expression this will work fine, or if you just use the other variables for do something else it will work fine too.

How does function work JavaScript?

A function in JavaScript is similar to a procedure—a set of statements that performs a task or calculates a value, but for a procedure to qualify as a function, it should take some input and return an output where there is some obvious relationship between the input and the output.

Can you nest functions in JavaScript?

Nested functions A function is called “nested” when it is created inside another function. It is easily possible to do this with JavaScript. Here the nested function getFullName() is made for convenience. It can access the outer variables and so can return the full name.


2 Answers

When you assign the function to the click handler, a closure is created.

Basically a closure is formed when you nest functions, inner functions can refer to the variables present in their outer enclosing functions even after their parent functions have already executed.

At the time that the click event is executed, the handler refers to the last value that the i variable had, because that variable is stored on the closure.

As you noticed, by wrapping the click handler function in order to accept the i variable as an argument, and returning another function (basically create another closure) it works as you expect:

for ( var i = 0; i < 4; i++ ) {   var a = document.createElement( "a" );   a.onclick = (function(j) { // a closure is created     return function () {       alert(j);      }   }(i));   document.getElementById( "foo" ).appendChild( a ); } 

When you iterate, actually create 4 functions, each function store a reference to i at the time it was created (by passing i), this value is stored on the outer closure and the inner function is executed when the click event fires.

I use the following snippet to explain closures (and a very basic concept of curry), I think that a simple example can make easier to get the concept:

// a function that generates functions to add two numbers function addGenerator (x) { // closure that stores the first number   return function (y){ // make the addition     return x + y;   }; }  var plusOne = addGenerator(1), // create two number adding functions     addFive = addGenerator(5);  alert(addFive(10)); // 15 alert(plusOne(10)); // 11 
like image 86
Christian C. Salvadó Avatar answered Oct 19 '22 20:10

Christian C. Salvadó


Without going into too much detail this essentially creates copies of the instance variables by wrapping them in a function that executes immediately and passes the back to the function that will be executed when the element gets clicked.

Think of it like this:

function() { alert(i); }  // Will expose the latest value of i (function(I) { return function() { alert(I); }; })(i); // Will pass the current                                                        // value of i and return                                                        // a function that exposes                                                        // i at that time 

So during each iteration of the loop you are actually executing a function that returns a function with the current value of the variable.

Which, if you imagine that you have 4 anchors in your loop you are creating 4 separate functions that can be visualized as..

function() { alert(0); }; function() { alert(1); }; function() { alert(2); }; function() { alert(3); }; 

I would consider looking into scope and closures with javascript as if you go down this road and don't understand exactly what is happening you can run into massive problems from unexpected behavior.

like image 37
Quintin Robinson Avatar answered Oct 19 '22 19:10

Quintin Robinson