2010-02-03 81 views
12

循环中的闭合件导致了我的问题。我想我不得不做另一个函数来返回一个函数来解决这个问题,但我不能让它与我的jQuery代码一起工作。for循环中的闭合件

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

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

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

自然地点击任何三个按钮将给予警告说3.我想要的功能是,点击按钮1会给出一个警告说1,按钮2会说2等。

我该如何做到这一点?

回答

10

查看bind方法。

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

从文档:

可选EVENTDATA参数 不常用。当提供时,这个 参数允许我们将其他 信息传递给处理程序。一个方便 使用这个参数是工作 各地引起关闭问题

+0

谢谢,它的工作原理。 – Rob 2010-02-03 14:16:56

+0

也为我工作! – bychkov 2011-03-24 21:02:46

+0

+1,解决我的问题 – anvd 2011-12-12 16:04:27

3

使用jQuery的距离。每个的功能 - 我猜你一个循环,通过类似的元素 - 所以使用类似添加点击:

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

未经测试,但我总是尽可能使用这种结构。

1

或者只是制造一个新的功能,如你所描述的。它应该是这样的:

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

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

我敢肯定迈赫达德的解决方案是行不通的。当你看到人们复制到一个临时变量时,通常会将“this”的值保存在内部子范围内。

+0

是的,他的解决方案没有工作,我认为他删除了它。 – Rob 2010-02-03 14:13:36

+0

这是我所知道的最佳答案。带绑定的代码很好,但该数据参数实际上是一个丑陋的黑客。这种方法的优点是,无论何时出现此问题(创建引用循环变量的闭包),它都可以工作,无论您是否拥有jQuery。 – 2010-02-03 14:27:06

+0

@Jason:虽然我同意这是一个伟大的答案,当然如果jQuery的没有提到和标签的问题,我会给出了答案,我不同意它是一个“丑陋的黑客攻击” - 这当然整洁。此外,半类似'Function.bind'是在第5版规范,所以你可以说为纯醇” JS最好的答案将是等效的原型法,将提供在JS的当前版本该功能。 http://snipplr.com/view/13987/functionbind/只是我能找到的一个例子,我知道有很多。 – 2010-02-03 14:48:41

5

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

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

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

由于环体是在每次迭代一个新的范围,索引变量被复制以在每次迭代时正确的值。

+0

由于这是很有必要知道 – Rob 2010-02-03 14:19:30

6

试试这个代码:

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的“计算机程序的结构和解释”中找到,Abelson(http://mitpress.mit.edu/sicp/全文在线提供,不是一个简单的阅读) - 参见3.2节。由于JavaScript实际上是C语言的Scheme,所以这个解释是可以的。

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

+0

同为darkporter的答案,但也有一些很好的阐述。 *“JavaScript实际上是C语言的Scheme”*每次有人第一次理解这个时,JS天使就会得到他的翅膀。 – 2010-02-03 14:41:46