【问题标题】:Why does one JavaScript closure work and the other doesn't?为什么一个 JavaScript 闭包起作用而另一个不起作用?
【发布时间】:2011-03-21 14:16:42
【问题描述】:

有两个版本,据说当用户点击第一个链接时会提示“1”,第二个链接会提示“2”等:

版本 1:

<a href="#" id="link1">click me</a>
<a href="#" id="link2">click me</a>
<a href="#" id="link3">click me</a>
<a href="#" id="link4">click me</a>
<a href="#" id="link5">click me</a>

<script type="text/javascript">
    for (i = 1; i <= 5; i++) {
        document.getElementById('link' + i).onclick = (function() {
            return function() {
                var n = i;
                alert(n);
                return false;
            }
        })();
    }
</script>

版本 2:

<a href="#" id="link1">click me</a>
<a href="#" id="link2">click me</a>
<a href="#" id="link3">click me</a>
<a href="#" id="link4">click me</a>
<a href="#" id="link5">click me</a>

<script type="text/javascript">
    for (i = 1; i <= 5; i++) {
        document.getElementById('link' + i).onclick = (function() {
            var n = i;
            return function() {
                alert(n);
                return false;
            }
        })();
    }
</script>

版本 1 将不起作用。版本 2 将。我想我知道原因,但想与其他人的解释比较一下为什么版本 1 不起作用。

【问题讨论】:

    标签: javascript scope closures


    【解决方案1】:

    版本 1 不起作用,因为每个人都共享一个公共变量“i”(在这种情况下是一个全局变量,因为你忘记了var)循环创建的“点击”处理函数。

    在第二个版本中,您使用小包装函数创建了一个新的词法作用域。这为每个“点击”处理程序提供了它自己的私有“i”。

    【讨论】:

      【解决方案2】:

      在第二个示例中,您创建了一个 var n = i;,它使 i 值在 onclick 函数内限定。而在第一个 onclick 函数仍然使用 i 的全局值

      我建议改用这种用法:

        for (i = 1; i <= 5; i++) {
          document.getElementById('link' + i).onclick = (function(i) {
            return function() {
              alert(i); 
              return false;
            }
          })(i);
        }
      

      在这种情况下,您将获得相同的行为,因为 i 将是 onclick 函数的局部变量,因为它是一个参数。

      【讨论】:

        【解决方案3】:

        First 不起作用,因为: i 是每个闭包的一部分。由于后缀增量运算符,经过 5 次迭代,现在 i 为 6。每次调用事件处理程序时,它都会从始终为 6 的闭包范围中获取 i 的值。

        第二部分有效:因为每个闭包都会在 n 中复制 i,所以 n 是每个闭包的一部分。

        【讨论】:

        • 从版本 1 来看,它不是每次都在制作 i 的新副本吗?
        • 没有。在版本 1 中,它不会在迭代 foreach 时进行复制。但点击时会复制。
        猜你喜欢
        • 1970-01-01
        • 2016-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-16
        • 1970-01-01
        相关资源
        最近更新 更多