Event.observe循环和变量

时间:2010-12-19 10:10:09

标签: javascript event-handling prototypejs

为了把事情放在上下文中,我正在通过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 ,这似乎是针对这些案例制作的,但可能没有得到它,因为它对我不起作用。

1 个答案:

答案 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,它们也可以。)