JavaScript中的奇怪内容“for”

时间:2010-06-30 14:04:58

标签: javascript jquery loops closures for-loop

我正在使用jQuery,我有一个我不明白的奇怪的事情。我有一些代码:

for (i = 1; i <= some_number; i++) {
    $("#some_button" + i).click(function() {
        alert(i);
    });
}

“#some_button”正如名字所说 - 它们是一些按钮。点击它们时,应该弹出一个带有它号码的方框,对吗?但他们没有。如果有4个按钮,它们总是弹出“5”(按钮计数+ 1)。为什么会这样?

6 个答案:

答案 0 :(得分:18)

它与JavaScript范围有关。您可以通过添加一个函数并让该函数调用自身并传入i:

来引入另一个范围,从而轻松绕过它
for (var i = 1; i <= some_number; i++) {
  (function(j) {
    $("#some_button" + j).click(function() {
      alert(j);
    });
  })(i);
}

这会创建一个闭包 - 当内部函数可以访问调用函数时不再存在的作用域时。有关详细信息,请参阅MDC上的this article

编辑:RE:自我调用函数:自调用函数是一个匿名调用自身的函数。您没有实例化它,也没有将它分配给变量。它采用以下形式(注意开头的parens):

(function(args) {
  // function body that might modify args
})(args_to_pass_in);

将此与问题联系起来,匿名函数的主体将是:

$("#some_button" + j).click(function() {
  alert(j);
});

将这些组合在一起,我们在第一个代码块中得到答案。匿名自调用函数期望一个名为j的参数。它会查找id为some_button的任何元素,其末尾的整数值为j(例如some_button1,some_button10)。只要单击其中一个元素,它就会警告j的值。解决方案的倒数第二行传递值i,这是调用匿名自调用函数的循环计数器。换句话说,它可能看起来像这样:

var innerFunction = function(j) {
  $("#some_button" + j).click(function() {
    alert(j);
  });
};

for (var i = 1; i <= some_number; i++) {
  innerFunction(i);
}

答案 1 :(得分:9)

for循环中有a very common closure problem

封闭在闭包中的变量共享相同的单一环境,因此在调用click回调时,循环将运行,i变量将指向最后一个条目。

您可以使用函数工厂解决更多关闭问题:

function makeOnClickCallback(i) {  
   return function() {  
      alert(i);
   };  
} 

var i;

for (i = 0; i < some_number; i++) {
    $("#some_button" + i).click(makeOnClickCallback(i));
}

如果你不熟悉闭包的工作方式,这可能是一个非常棘手的话题。您可以查看以下Mozilla文章以获得简要介绍:

答案 2 :(得分:2)

因为在您点击它们的那一刻,我= = 5。

答案 3 :(得分:0)

这是因为闭包在JavaScript中的工作原理。您正在创建的5个函数中的每个函数基本上都共享相同的i变量。在创建函数时,函数内部i的值不会被评估,但是当发生click事件时,i的值为5。

有各种解决方法(当这种行为不是你想要的时候)。一个(如果你有一个简单的函数,就像你在这里一样)是使用Function构造函数而不是函数文字:

$("#some_button" + i).click(new Function("alert("+i+")");

答案 4 :(得分:-1)

  (function (some_number) {
    for (i = 1; i <= some_number; i++) {
      $("#some_button" + i).click(function() {
        alert(i);
      });
    }
  })(some_number);

将功能包裹在外面因为速度和事实我将继续重置。

答案 5 :(得分:-1)

这是非常聪明的代码。如此聪明,这是一个关于SO的问题。 :)我已经完全回避了这个问题,将代码缩小了,只是为了有机会在六个月之后理解它(或让同事理解它)。闭包有它们的位置,但在这种情况下,我会避免它们支持更容易理解的代码。

也许,我会将相同的功能附加到所有按钮,这将从事件中获取按钮,从ID中删除“some_button”,并提醒结果。不是那么漂亮,但我保证办公室里的每个人都可以一目了然。