views:

455

answers:

5

Take below code iterates over 6 input buttons and attaches an onclick event to every button that alerts the index number of the respective iteration:

for (var i = 1; i < 6; ++i) {
    var but = document.getElementById('b_' + i);
    (function (el) {
        var num = i;
        but.onclick = function () {
            alert(num);
        };
    })(but);
}

As you can see, in each iteration there is a self-invoking function that creates a scope to store the iteration index in that scope.

I have always used this type of pattern to attach an event that is dependant on a variable that is changed during iterations.


Can anyone explain to me exactly why the above works, and how the num variable is captured in the scope?

Also, is the self-invoking function used above called a closure ?

A: 

Wouldn't that mean that the var i defined outside the closure is a global variable, thus giving the self-invoking function access to it?

Marco
`i` is global only if the outer loop is evaluated in a global context. It's because `i` is in scope when the function is defined that makes `i` visible in the function. Also, if you have a question about a question, comment. Answering is for answers, and you now have enough points to leave comments.
outis
But how is the scope of the self-invoking function retained after each iteration of the loop ?
Andreas Grech
That's the magic of closures. It's what they do.
outis
@outis, sorry about that, I'm apparently not used to this structure yet, I'll keep what you said in mind though.
Marco
+1  A: 

Hey guys. Yep it is a closure. If you want to know what exactly occurs when function is creating then study following article. http://www.jibbering.com/faq/faq%5Fnotes/closures.html

Danil
A: 

Each time through the loop, evaluating function (el) {...} creates a new anonymous function, which is immediately invoked. Within the anonymous function, a variable named num is created (because JS doesn't do static variables, it's a new one each time). num is assigned the value of i when the function is invoked (which is immediately). This gives us 6 anonymous functions and 6 nums, each holding the values 1 through 6.

With each invocation of the anonymous function, an inner anonymous function is created and stored as the click handler. The inner function references a num. As a result, a closure is created which ensure that when the outer function exits, num isn't destroyed. Should the inner function ever be discarded, num will soon follow.

outis
+4  A: 

Yes this is a closure.

Everytime a function is executed a new object is created to hold (as its properties) the variables that are declared with var and every function declared inside it. This object is called the execution context (or sometimes the scope object).

Everytime a function is declared (or defined in an expression) the new function has attached to it the execution context object that is current. This creates what is known as a scope chain.

When executing code needs to resolve an identifier to a value it first looks for it in the properties of the current execution context. If the identifier is not found it uses the exection context object attached to the function that is being executed. It keeps going up the scope chain until it reaches the global level.

In your example each time "self-invoking function" gets executed a new execution context object is create holding the properies el and num. Since the function assigned to onclick is created inside this execution context you will get a new instance of this function each time. These instances will each have the corresponding execution context object attached. Hence the first will have the execution context when num has been assigned 1, the second will have the execution context where num has been assigned 2 and so on.

When each of the onclick functions run the code will initially look for the identifier num in the current execution context. However this inner function doesn't var a num so its not found. So Javascript looks to the execution context attached to the function when it was created. Here it will find num, the num will contain the value assigned to it during that iteration as described above.

AnthonyWJones
I've read it being called the "Activation Object" usually.
Breton
A: 
for (var i = 1; i < 6; ++i) {
    var but = document.getElementById('b_' + i);
    (function (el) {
        var num = i;
        but.onclick = function () {
            alert(num);
        };
    })(but);
}

Now lets start the execution of the loop
initially i=1,but= domelement with id ='b1'
now comes the function invoke,
ok it calls the inner function(with parameter el) with value of parameter of but('b1') and starts executing it that is what invoking actually means execute it now.
Now inside it ,
new instance of num is assigned 1
but.onclick is assigned a function so stores function in memory also sees that it accesses num so num is now closed variable that means its lifetime is increased so as to be accessed by onclick function when invoked.

Next iteration
now value of i=2,but= domelement with id ='b2' now comes the function invoke,
it calls the inner function(with parameter el) with value of parameter of but(value='b2') .
Now inside it ,
new instance of num is assigned 2
but.onclick is assigned a function so stores function in memory also sees that it accesses num so num is now closed variable that means its lifetime is increased so as to be accessed by onclick function when invoked.
Similary all others are exectuted till the loop terminates.

Prahlad