我正在使用jQuery,我有一个我不明白的奇怪的事情。我有一些代码:
for (i = 1; i <= some_number; i++) {
$("#some_button" + i).click(function() {
alert(i);
});
}
“#some_button”正如名字所说 - 它们是一些按钮。点击它们时,应该弹出一个带有它号码的方框,对吗?但他们没有。如果有4个按钮,它们总是弹出“5”(按钮计数+ 1)。为什么会这样?
答案 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”,并提醒结果。不是那么漂亮,但我保证办公室里的每个人都可以一目了然。