以下代码迭代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
变量?
此外,上面使用的自调用函数是closure
?
答案 0 :(得分:8)
是的,这是一个关闭。
每次函数执行时,都会创建一个新对象来保存(作为其属性)使用var
声明的变量以及在其中声明的每个函数。该对象称为执行上下文(或有时称为范围对象)。
每次函数声明(或在表达式中定义)时,新函数都会附加当前的执行上下文对象。这创建了所谓的范围链。
当执行代码需要将标识符解析为值时,它首先在当前执行上下文的属性中查找它。如果未找到标识符,则它使用附加到正在执行的函数的exection上下文对象。它一直在范围链上升,直到达到全球水平。
在您的示例中,每次执行“自调用函数”时,都会创建一个新的执行上下文对象,其中包含属性el
和num
。由于分配给onclick的函数是在此执行上下文中创建的,因此每次都会获得此函数的新实例。这些实例将各自附加相应的执行上下文对象。因此,第一个将在num
被分配1时具有执行上下文,第二个将具有已分配num
的执行上下文2,依此类推。
当每个onclick函数运行时,代码将首先在当前执行上下文中查找标识符num
。但是这个内部函数不会变量,因此找不到它。所以Javascript在创建函数时查看附加到函数的执行上下文。在此处,它会找到num
,num
将包含在此迭代期间分配给它的值,如上所述。
答案 1 :(得分:1)
答案 2 :(得分:0)
这是不是意味着在var i
之外定义的closure
是一个全局变量,从而赋予自调用函数访问权限?
答案 3 :(得分:0)
每次循环时,评估function (el) {...}
都会创建一个新的匿名函数,该函数会立即被调用。在匿名函数中,创建了一个名为num
的变量(因为JS不执行静态变量,每次都是新变量)。调用函数时({]立即为num
赋值i
。这给了我们6个匿名函数和6个num
s,每个函数保存值1到6。
每次调用匿名函数时,都会创建一个内部匿名函数并将其存储为单击处理程序。内部函数引用num
。结果,创建了一个闭包,确保当外部函数退出时,num
不会被销毁。如果内部函数被丢弃,num
将很快跟进。
答案 4 :(得分:0)
for (var i = 1; i < 6; ++i) {
var but = document.getElementById('b_' + i);
(function (el) {
var num = i;
but.onclick = function () {
alert(num);
};
})(but);
}
现在让我们开始执行循环
最初 i = 1,但是= id ='b1'的圆顶元素
现在来函数调用,
好吧,它调用内部函数(带参数el),参数值为(''b1')
并开始执行它,这实际上是调用意味着现在执行它
现在在里面,
新的num实例被分配1
但是.onclick被分配了一个函数,所以在内存中存储函数也看到它访问num所以num现在是闭合变量,这意味着它的生命周期增加,以便在调用时被onclick函数访问。
下一次迭代
现在i = 2的值,但是= id ='b2'的domelement
现在来函数调用,
它调用内部函数(带参数el),参数值为(value ='b2')
现在在里面,
新的num实例被分配2
但是.onclick被分配了一个函数,所以存储函数在内存中也看到它访问num所以num现在是闭合变量,这意味着它的生命周期增加,以便在被调用时被onclick函数访问。
相似的所有其他人都被解雇,直到循环结束。