为了把事情放在上下文中,我正在通过Ajax加载一个项目列表,为每个项目创建一个包含主要信息的div,并希望在点击它时在页面上显示详细信息。所以我在onSuccess中有这个代码:
items = transport.responseText.evalJSON(); // my list of objects that contains all the details I'll need for that page
for (var itemID in items)
{
newDiv = ... // Creating my div with main infos
$('myDiv').appendChild(newDiv);
// More code to make everything look pretty and that works fine
Event.observe(newDiv, 'click', function() { loadItem(itemID); });
}
loadItem是我的功能,它将显示所有项目详细信息。我的问题是 itemID 在创建observe事件时不会被其值替换,因此它总是为所有项返回相同的ID。
知道如何解决这个问题吗?我在原型doc上检查了 bind ,这似乎是针对这些案例制作的,但可能没有得到它,因为它对我不起作用。
答案 0 :(得分:5)
要获得影响最小的修复,请将Event.observe
行替换为:
Event.observe(newDiv, 'click', loadItem.curry(itemID));
说明:
在原始代码中,事件处理函数正在创建 close over (具有持久引用)itemID
变量,因此将使用该变量的值何时将事件处理程序称为 ,而不是在将其分配给事件时。对于所有处理函数,该值将是itemID
在循环中的最后一个值。 More about closures here.
使用最小影响修订代码,我们使用Prototype的curry
函数,它将为您创建一个函数,在调用时,将使用您提供的参数curry
调用基础函数。 (这个名字是from mathematics; Haskell Curry想出了这个技术,虽然有人认为他不是第一个这样做的人。)我们可以自己做同样的事情:
items = transport.responseText.evalJSON(); // my list of objects that contains all the details I'll need for that page
for (var itemID in items)
{
newDiv = ... // Creating my div with main infos
$('myDiv').appendChild(newDiv);
// More code to make everything look pretty and that works fine
Event.observe(newDiv, 'click', prepLoadItem(itemID));
}
function prepLoadItem(id) {
return function() {
loadItem(id);
};
}
...但是因为Prototype具有通用功能,所以我们没有。
偏离主题:items
是否为数组?如果没有,请忽略此非主题评论。如果是这样,不使用for..in
来循环它,或者至少,除非你采取一些预防措施,否则上面的代码不会正确地执行它。 Details here,但for..in
不用于循环遍历数组的索引;它用于循环对象的属性。数组对象可能具有除数组索引之外的属性(实际上,如果您使用的是Prototype,它们也可以。)