for 循环中的闭包

发布于 2024-08-20 11:34:38 字数 344 浏览 1 评论 0原文

循环中的闭包给我带来了问题。我想我必须创建另一个返回函数的函数来解决问题,但我无法让它与我的 jQuery 代码一起工作。

这是简化形式的基本问题:

function foo(val) {
  alert(val);
}

for (var i = 0; i < 3; i++) {
  $('#button'+i).click(function(){
    foo(i);
  });
}

自然地,单击三个按钮中的任何一个都会发出警报,提示“3”。我想要的功能是,单击按钮 1 将发出警报,提示“1”,按钮 2 将发出警报,提示“2”等。

如何我可以让它这样做吗?

Closures in a loop are causing me problems. I think I have to make another function that returns a function to solve the problem, but I can't get it to work with my jQuery code.

Here is the basic problem in a simplified form:

function foo(val) {
  alert(val);
}

for (var i = 0; i < 3; i++) {
  $('#button'+i).click(function(){
    foo(i);
  });
}

Naturally clicking on any of the three buttons will give an alert saying 3. The functionality I want is that clicking on button 1 will give an alert saying 1, button 2 will say 2 etc.

How can I make it do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

你是暖光i 2024-08-27 11:34:38

请参阅 bind 方法。

$('#button'+i).bind('click', {button: i}, function(event) {
  foo(event.data.button);
});

来自文档:

可选的 eventData 参数是
不常用。当提供时,这
参数允许我们传递额外的
信息给处理程序。随手一用
使用此参数即可工作
围绕关闭引起的问题

See the bind method.

$('#button'+i).bind('click', {button: i}, function(event) {
  foo(event.data.button);
});

From the docs:

The optional eventData parameter is
not commonly used. When provided, this
argument allows us to pass additional
information to the handler. One handy
use of this parameter is to work
around issues caused by closures

心欲静而疯不止 2024-08-27 11:34:38

试试这段代码:

function foo(val) {
  alert(val);
}

var funMaker = function(k) {
  return function() {
    foo(k);
  };
};

for (var i = 0; i < 3; i++) {
  $('#button'+i).click(funMaker(i));
}

这里有一些要点:

  • JavaScript 是函数作用域的。如果您想要一个新的(“更深”)范围,您需要创建一个函数来保存它。
  • 该解决方案是特定于 Javascript 的,无论有没有 jQuery,它都可以工作。
  • 该解决方案之所以有效,是因为 i 的每个值都被复制到新的作用域中作为 k,并且从 funMaker 返回的函数在 k 附近关闭 (在循环中不会改变),而不是在 i 周围(在循环中会改变)。
  • 您的代码不起作用,因为您传递给 click 的函数不“拥有”i,它会关闭 i它的创建者,并且 i 在循环中发生变化。
  • 该示例可以使用内联的 funMaker 编写,但我通常使用此类辅助函数来使事情更清晰。
  • funMaker 的参数是 k,但这没有什么区别,它可以是 i 没有任何问题,因为它存在于函数funMaker
  • 对“环境”评估模型最清晰的解释之一可以在Sussman & Co的《计算机程序的结构和解释》中找到。 Abelson(http://mitpress.mit.edu/sicp/ 全文可在线获取,而非易于阅读) - 请参阅第 3.2 节。由于JavaScript实际上是C语法的Scheme,所以这个解释是可以的。

编辑:修正了一些标点符号。

Try this code:

function foo(val) {
  alert(val);
}

var funMaker = function(k) {
  return function() {
    foo(k);
  };
};

for (var i = 0; i < 3; i++) {
  $('#button'+i).click(funMaker(i));
}

Some important points here:

  • JavaScript is function scoped. If you want a new ('deeper') scope, you need to create a function to hold it.
  • This solution is Javascript specific, it works with or without jQuery.
  • The solution works because each value of i is copied in a new scope as k, and the function returned from funMaker closes around k (which doesn't change in the loop), not around i (which does).
  • Your code doesn't work because the function that you pass to click doesn't 'own' the i, it closes over the i of its creator, and that i changes in the loop.
  • The example could have been written with funMaker inlined, but I usually use such helper functions to make things clearer.
  • The argument of funMaker is k, but that makes no difference, it could have been i without any problems, since it exists in the scope of the function funMaker.
  • One of the clearest explanation of the 'Environment' evaluation model is found in 'Structure and Interpretation of Computer Programs', by Sussman & Abelson (http://mitpress.mit.edu/sicp/ full text available online, not an easy read) - see section 3.2. Since JavaScript is really Scheme with C syntax, that explanation is OK.

EDIT: Fixed some punctuation.

韶华倾负 2024-08-27 11:34:38

@Andy 解决方案是最好的。但您也可以使用 Javascript 作用域来帮助您保存闭包中的值。

您可以通过执行匿名函数在循环体中创建新作用域来实现此目的。

for (var i = 0; i < 3; i++) {
  (function(){
    var index = i; 
    $('#button'+index).click(function(){
      foo(index);
    });
  })();
}

由于循环体在每次迭代时都是一个新范围,因此索引变量在每次迭代时都会使用正确的值进行复制。

@Andy solution is the nicest. But you can also use Javascript scoping to help you save the value in your closure.

You do so by creating a new scope in your loop body by executing an anonymous function.

for (var i = 0; i < 3; i++) {
  (function(){
    var index = i; 
    $('#button'+index).click(function(){
      foo(index);
    });
  })();
}

Since the loop body is a new scope at each iteration, the index variable is duplicated with the correct value at each iteration.

忘你却要生生世世 2024-08-27 11:34:38

使用 jquery 中的 .each 函数 - 我猜你循环遍历类似的元素 - 所以使用类似的内容添加点击:

$(element).children(class).each(function(i){
   $(this).click(function(){
      foo(i);
   });
});

未测试,但我总是在可能的情况下使用这种结构。

Use the .each function from jquery - I guess you a looping through similar elements - so add the click using something like:

$(element).children(class).each(function(i){
   $(this).click(function(){
      foo(i);
   });
});

Not tested but I always use this kind structure where possible.

静待花开 2024-08-27 11:34:38

或者只是制造一个新功能,正如您所描述的。它看起来像这样:

function foo(val) {
    return function() {
        alert(val);
    }
}

for (var i = 0; i < 3; i++) {
    $('#button'+i).click(foo(i));
}

我很确定迈赫达德的解决方案不起作用。当您看到人们复制到临时变量时,通常是为了保存“this”的值,该值在内部子作用域内可能不同。

Or just manufacture a new function, as you describe. It would look like this:

function foo(val) {
    return function() {
        alert(val);
    }
}

for (var i = 0; i < 3; i++) {
    $('#button'+i).click(foo(i));
}

I'm pretty sure Mehrdad's solution doesn't work. When you see people copying to a temporary variable, it's usually to save the value of "this" which may be different within an inner child scope.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文