JavaScript中的奇怪内容“for”

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

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

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

它与JavaScript范围有关。 您可以通过添加一个函数并让该函数调用自身并传入i来引入另一个范围,从而轻松解决它:

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

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

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

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

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

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

将这些组合在一起,我们在第一个代码块中得到答案。 匿名自调用函数期望一个名为j的参数。 它查找id为some_button任何元素,其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); } 

你在for循环中遇到了一个非常常见的闭包问题 。

封闭在闭包中的变量共享相同的单个环境,因此在调用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文章以获得简要介绍:

  • 使用闭包

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

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

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

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

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

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

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