我有以下代码片段。
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function () {
alert(i);
};
document.body.appendChild(link);
}
}
上面的代码用于生成 5 个链接,并将每个链接与警报事件绑定(bind)以显示当前链接 id。但这不起作用。当您单击生成的链接时,它们都会显示“链接 5”。
但是下面的代码片段符合我们的预期。
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function (num) {
return function () {
alert(num);
};
}(i);
document.body.appendChild(link);
}
}
以上2段摘自here 。正如作者的解释所示,似乎闭包创造了魔力。
但是它是如何工作的以及闭包如何使其工作都超出了我的理解范围。为什么第一个不起作用而第二个起作用?谁能详细解释一下这个魔法?
最佳答案
Quoting myself有关第一个示例的解释:
JavaScript's scopes are function-level, not block-level, and creating a closure just means that the enclosing scope gets added to the lexical environment of the enclosed function.
After the loop terminates, the function-level variable i has the value 5, and that's what the inner function 'sees'.
在第二个示例中,对于每个迭代步骤,外部函数文字将计算为具有自己的作用域和局部变量 num
的新函数对象,其值设置为 的当前值>我
。由于 num 从未被修改,因此它将在闭包的生命周期内保持不变:下一个迭代步骤不会覆盖旧值,因为函数对象是独立的。
请记住,这种方法效率相当低,因为必须为每个链接创建两个新的函数对象。这是不必要的,因为如果您使用 DOM 节点进行信息存储,它们可以轻松共享:
function linkListener() {
alert(this.i);
}
function addLinks () {
for(var i = 0; i < 5; ++i) {
var link = document.createElement('a');
link.appendChild(document.createTextNode('Link ' + i));
link.i = i;
link.onclick = linkListener;
document.body.appendChild(link);
}
}
关于Javascript 臭名昭著的循环问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34346768/