我有以下代码片段。
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个链接,并将每个链接与警报事件绑定以显示当前链接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); } }
这里引用了以上两个片段。
但是它是如何工作的以及 关闭 是如何工作的,这些都是我无法理解的。为什么第一个不起作用而第二个却起作用?任何人都可以对魔术进行详细说明吗?
谢谢。
解释第一个示例:
JavaScript的作用域是函数级的,而不是块级的,创建闭包只是意味着将封闭范围添加到封闭函数的词法环境中。 循环终止后,函数级变量i的值为5,这就是内部函数所看到的。
JavaScript的作用域是函数级的,而不是块级的,创建闭包只是意味着将封闭范围添加到封闭函数的词法环境中。
循环终止后,函数级变量i的值为5,这就是内部函数所看到的。
在第二个示例中,对于每个迭代步骤,外部函数文字将评估为具有自己的作用域和局部变量的新函数对象num,其值设置为的当前值i。正如num从未修改过的那样,它将在闭包的整个生命周期中保持不变:由于函数对象是独立的,下一个迭代步骤不会覆盖旧值。
num
i
请记住,这种方法效率很低,因为必须为每个链接创建两个新的功能对象。这是不必要的,因为如果您使用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); } }