Javascript 中具有自调用函数的作用域
下面的代码迭代了 6 个输入按钮,并将一个 onclick
事件附加到每个按钮,以提醒相应迭代的索引号:
for (var i = 1; i < 6; ++i) {
var but = document.getElementById('b_' + i);
(function (el) {
var num = i;
but.onclick = function () {
alert(num);
};
})(but);
}
如您所见,在每次迭代中都有一个自调用函数,该函数创建用于在该范围内存储迭代索引的范围。
我一直使用这种类型的模式来附加一个依赖于迭代期间更改的变量的事件。
谁能向我解释一下为什么上面的方法有效,以及如何在范围内捕获 num 变量?
另外,上面使用的自调用函数称为闭包吗?
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
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的,这是一个闭包。
每次执行函数时,都会创建一个新对象来保存(作为其属性)用
var
声明的变量以及在其中声明的每个函数。该对象称为执行上下文(有时称为作用域对象)。每次声明函数(或在表达式中定义)时,新函数都会附加当前的执行上下文对象。这创建了所谓的作用域链。
当执行代码需要将标识符解析为值时,它首先在当前执行上下文的属性中查找它。如果未找到标识符,它将使用附加到正在执行的函数的执行上下文对象。它不断沿着作用域链向上延伸,直到达到全局级别。
在您的示例中,每次执行“自调用函数”时,都会创建一个新的执行上下文对象,其中包含属性
el
和num
。由于分配给 onclick 的函数是在此执行上下文中创建的,因此您每次都会获得该函数的一个新实例。这些实例都将附加相应的执行上下文对象。因此,当num
被分配 1 时,第一个将具有执行上下文,第二个将具有num
被分配 2 时的执行上下文,依此类推。当每个 onclick 函数运行时,代码首先会在当前执行上下文中查找标识符
num
。然而这个内部函数没有 var num 所以它没有找到。因此,Javascript 在创建函数时会查看附加到该函数的执行上下文。在这里它将找到num
,num
将包含在迭代期间分配给它的值,如上所述。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
andnum
. 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 whennum
has been assigned 1, the second will have the execution context wherenum
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 findnum
, thenum
will contain the value assigned to it during that iteration as described above.嘿伙计们。是的,这是一个关闭。如果您想知道创建函数时到底发生了什么,请学习以下文章。
http://www.jibbering.com/faq/faq_notes/closures.html
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
这是否意味着在闭包外部定义的 var i 是一个全局变量,从而允许自调用函数访问它?
Wouldn't that mean that the
var i
defined outside theclosure
is a global variable, thus giving the self-invoking function access to it?每次循环时,计算
function (el) {...}
都会创建一个新的匿名函数,并立即调用该函数。在匿名函数中,创建了一个名为num
的变量(因为JS不做静态变量,所以每次都是一个新变量)。当调用该函数时(立即),num
被赋予i
的值。这为我们提供了 6 个匿名函数和 6 个num
,每个函数保存值 1 到 6。每次调用匿名函数时,都会创建一个内部匿名函数并将其存储为点击处理程序。内部函数引用
num
。结果,创建了一个闭包,确保当外部函数退出时,num
不会被销毁。如果内部函数被丢弃,num
很快就会被丢弃。Each time through the loop, evaluating
function (el) {...}
creates a new anonymous function, which is immediately invoked. Within the anonymous function, a variable namednum
is created (because JS doesn't do static variables, it's a new one each time).num
is assigned the value ofi
when the function is invoked (which is immediately). This gives us 6 anonymous functions and 6num
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.现在让我们开始执行循环
最初 i=1,但是= id ='b1' 的 domelement
现在是函数调用,
好的,它调用内部函数(带参数 el),参数值为 but('b1')
并开始执行它,这就是调用实际上意味着立即执行它。
现在在里面,
num 的新实例被分配 1
但是.onclick 被分配了一个函数,因此在内存中存储函数也会看到它访问 num,因此 num 现在是封闭变量,这意味着它的生命周期增加,以便在调用时被 onclick 函数访问。
下一次迭代< /strong>
现在 i=2 的值,但是= id ='b2' 的 domelement
现在是函数调用,
它调用内部函数(带参数 el),参数值为 but(value='b2') 。
现在在里面,
num 的新实例被分配 2
但是.onclick 被分配了一个函数,因此在内存中存储函数也会看到它访问 num,因此 num 现在是封闭变量,这意味着它的生命周期增加,以便在调用时被 onclick 函数访问。
类似地,所有其他的都会被执行,直到循环终止。
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.