小编典典

JavaScript的循环问题?

javascript

我有以下代码片段。

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);
    }
}

这里引用了以上两个片段。

但是它是如何工作的以及 关闭 是如何工作的,这些都是我无法理解的。为什么第一个不起作用而第二个却起作用?任何人都可以对魔术进行详细说明吗?

谢谢。


阅读 384

收藏
2020-04-22

共1个答案

小编典典

解释第一个示例:

JavaScript的作用域是函数级的,而不是块级的,创建闭包只是意味着将封闭范围添加到封闭函数的词法环境中。

循环终止后,函数级变量i的值为5,这就是内部函数所看到的。

在第二个示例中,对于每个迭代步骤,外部函数文字将评估为具有自己的作用域和局部变量的新函数对象num,其值设置为的当前值i。正如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);
    }
}
2020-04-22