Scope with a self-invoking function in Javascript
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开发者_如何学Python 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
?
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.
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_notes/closures.html
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?
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 num
s, 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.
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.
精彩评论