我有以下CoffeeScript代码:

for date of dates
    Dom.section !->
        Dom.div !->
            Dom.text if date.attending then 'Y' else 'N'
            Dom.onTap !->
                Dom.text date.id


将其转换为以下JavaScript(根据coffeescript.org)

var date;

for (date in dates) {
  Dom.section(!function() {
    return Dom.div(!function() {
      Dom.text(date.attending ? 'Y' : 'N');
      return Dom.onTap(!function() {
        return Dom.text(date.id);
      });
    });
  });
}


不要打扰代码的确切功能,因为我正在使用Happening的API(在CoffeeScript中使用它可以制作插件的新对话应用程序),因此,您无论如何也不会理解它。

我会解释一下:


dates是长度为10的数组,其中包含对象。这些对象包含iddayyearattending之类的键。
我遍历所有日期,并在屏幕上的“部分”中呈现这些日期。
每个部分包含几个div(为简单起见,在上面的示例中只有一个)。
上面的div包含一些文本。用户正在参加活动时为“ Y”,否则则为“ N”。
当用户在该div上点击(“ onTap”事件)时,它将更新本地存储和共享存储(在上面的示例中,它将仅添加一些用于调试的文本)。


一切正常,它在正确的部分显示了正确的日期和参加者人数。因此,date对象包含正确的数据。

问题

我遇到的问题是当我使用onTap事件点击div时。当我点击它时,它将始终使用显示的最后日期。假设我有01-12-1410-12-14的日期。我点击05-12-14,它将在屏幕上添加ID 10-12-14作为文本。经过长时间的折腾和诅咒,我发现了造成这种情况的原因,但我不知道如何解决。

请参阅JavaScript的第一行(第二个代码示例)。如您所见,它声明了一个全局变量date。一切都可以正常显示,但是当我单击某些内容时,它将引用date,但是由于date在循环的最后一次迭代中已更新,因此它将始终使用该id。

所以。如何确保date在每个迭代循环中保持私有,并确保在事件中使用正确的值?

注意

for k, v in dates也不起作用,因为它也使k全局化。因此,简单地使用dates[k].id是行不通的。

最佳答案

它不是在声明全局变量,而只是声明该代码的全局变量。如果它在一个函数中,那将不是全局的。

该问题与全局变量无关。这是因为闭包是如何工作的。闭包对它们关闭的变量有持久的引用,而不是创建闭包时值的副本。因此,您为onTap处理程序创建的所有函数都使用相同的单个date对象。

为了防止这种情况,请给他们每个人自己的东西以使其关闭。如果dates是数组,请使用forEach

(请注意那些不熟悉CoffeeScript但不熟悉的人:!前面的->不是通常的!运算符。对幸福的理解是对CoffeeScript的扩展,使得使用!->而不是->声明函数,则不会生成Coffeescript通常具有的隐式返回值。(感谢Erik Dolor指出了这一点。)

所以:

dates.forEach (date) !->
    Dom.section !->
        Dom.div !->
            Dom.text if date.attending then 'Y' else 'N'
            Dom.onTap !->
                Dom.text date.id


...变成了这个JavaScript:

dates.forEach(function(date) {
  Dom.section(function() {
    Dom.div(function() {
      Dom.text(date.attending ? 'Y' : 'N');
      Dom.onTap(function() {
        Dom.text(date.id);
      });
    });
  });
});


现在,为forEach回调的每次迭代创建的闭包将覆盖该回调迭代的参数date,该参数不变。

07-24 09:47
查看更多