javascript:使用闭包来“冻结”for循环中i的值

时间:2014-02-10 16:45:19

标签: javascript closures

此问题取自此处接受的答案中的第一个问题:https://stackoverflow.com/questions/1684917/what-questions-should-a-javascript-programmer-be-able-to-answer

<a href="#">text</a><br><a href="#">link</a>
 <script>
 var as = document.getElementsByTagName('a');
 for ( var i = as.length; i--; ) {
    as[i].onclick = function() {
        alert(i);
        return false;
    }
 }
</script>

为什么锚点在点击时会在循环内警告-1而不是各自的计数器?如何修复代码,以便提醒正确的数字? (提示:关闭)

2 个答案:

答案 0 :(得分:4)

onclick触发i的值为-1时(因为这是i将获得的最后一个值)。

解决方案是创建一个闭包,将迭代的那个i 的值绑定到onclick-listener。

解决这个问题的一种可能方法是:

for ( var i = as.length; i--; ) {
    as[i].onclick = (function(actually_i) {
        return function () {
            alert(actually_i);
            return false;
        }
    }(i)) // pass in i
}

此代码还有其他问题。我就是这样写的:

for (var i; i < as.length; i += 1) {
    as[i].addEventListener("click", (function(actually_i) {
        return function (event) {
            event.preventDefault();
            alert(actually_i);
        }
    }(i)) // pass in i
}
  • i--构建过于聪明并导致错误
  • 最好使用addEventListener而不是分配onclick(模块化问题)。
  • preventDefault是打算,而不是stopPropagation。 return false同时做到并且总是错误的。

答案 1 :(得分:2)

当前情况:

  1. 循环1(i = 1):设置点击第一个链接。
  2. 循环2(i = 0):设置点击第二个链接。
  3. 第二次循环后,i等于-1
  4. 点击发生:i仍然等于-1
  5. 使用IIFE可以创建一个全新的上下文,其中i的值不再与i无关。然后,考虑下面的示例,术语“closure”指的是j与返回函数之间的关系,它将作为点击处理程序:

    var as = document.getElementsByTagName('a');
    for ( var i = as.length; i--; ) {
        as[i].onclick = function (j) {
            return function () {
                alert(i + ' ' + j);
                return false;
            };
        }(i);
    }