JavaScript臭名昭著的循环问题?[重复]

2020/10/13 16:40 · javascript ·  · 0评论

我有以下代码片段。

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,这就是内部函数所看到的。

在第二个示例中,对于每个迭代步骤,外部函数文字将评估为具有自己的作用域和局部变量的新函数对象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);
    }
}

I like to write simple explanations for thick people, because I'm thick so here goes ...

We have 5 divs on the page, each with an ID ... div1, div2, div3, div4, div5

jQuery can do this ...

for (var i=1; i<=5; i++) {
    $("#div" + i).click ( function() { alert ($(this).index()) } )
}

But really addressing the problem (and building this up slowly) ...

STEP 1

for (var i=1; i<=5; i++) {
    $("#div" + i).click (
        // TODO: Write function to handle click event
    )
}

STEP 2

for (var i=1; i<=5; i++) {
    $("#div" + i).click (
        function(num) {
            // A functions variable values are set WHEN THE FUNCTION IS CALLED!
            // PLEASE UNDERSTAND THIS AND YOU ARE HOME AND DRY (took me 2 years)!
            // Now the click event is expecting a function as a handler so return it
            return function() { alert (num) }
        }(i) // We call the function here, passing in i
    )
}

SIMPLE TO UNDERSTAND ALTERNATIVE

If you can't get your head around that then this should be easier to understand and has the same effect ...

for (var i=1; i<=5; i++) {

    function clickHandler(num) {    
        $("#div" + i).click (
            function() { alert (num) }
        )
    }
    clickHandler(i);

}

This should be simple to understand if you remember that a functions variable values are set when the function is called (but this uses the exact same thought process as before)

基本上,在第一个示例中,您将i内部onclick处理程序直接绑定i外部onclick处理程序。因此,当i外部onclick处理程序更改时,i内部onclick处理程序也更改。

In the second example, instead of binding it to the num in the onclick handler, you're passing it into a function, which then binds it to the num in the onclick handler. When you pass it into the function, the value of i is copied, not bound to num. So when i changes, num stays the same. The copy occurs because functions in JavaScript are "closures", meaning that once something is passed into the function, it's "closed" for outside modification.

其他人已经解释了怎么回事,这是一个替代解决方案。

function addLinks () {
  for (var i = 0, link; i < 5; i++) {
    link = document.createElement("a");
    link.innerHTML = "Link " + i;

    with ({ n: i }) {
      link.onclick = function() {
        alert(n);
      };
    }
    document.body.appendChild(link);
  }
}

基本上,穷人束手无策。

在第一个示例中,您只需将此函数绑定到onclick事件:

function() {alert(i);};

这意味着,在单击事件中,js应该警告addlink函数i变量的值。由于for循环(),其值将为5。

在第二个示例中,您生成一个要与另一个函数绑定的函数:

function (num) {
  return function () { alert(num); };
}

这意味着:如果使用值调用,请返回一个将警告输入值的函数。例如,通话function(3)将返回function() { alert(3) };

您在每次迭代时都使用值i调用此函数,因此为每个链接创建了单独的onclick函数。

关键是在第一个示例中,您的函数包含一个变量引用,而在第二个示例中,借助外部函数,您将引用替换为实际值。这之所以称为闭包,是因为您将变量的当前值“封装”在函数中,而不是保留对其的引用。

本文地址:http://javascript.askforanswer.com/javascriptchoumingzhaozhudexunhuanwentizhongfu.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!