Nodejs + Coffeescript 的变量范围

Posted

技术标签:

【中文标题】Nodejs + Coffeescript 的变量范围【英文标题】:Variable scope with Nodejs + Coffeescript 【发布时间】:2014-08-29 18:48:38 【问题描述】:

我很难找到这个。

...

for offset in [1..3]
  queryDate = moment().subtract(offset, 'days')
  console.log offset    # gives 1, 2, 3

  # check if a row already exists for this day
  Datum.findOne  date:  $lte: queryDate.toDate()  , (err, datum) ->
    console.log offset # gives 4, 4, 4

...

确定变量范围以便它们可以在回调中使用的正确方法是什么?

【问题讨论】:

【参考方案1】:

使用包装函数应该可以工作。

# this is a wrapper to setTimeout
# it's used as a substitute to Datum.findOne in the question
delay = (ms, func) -> setTimeout func, ms

myRange = 4

myWrapper = (offset, range) ->             # range could be queryDate
  delay 0, ->                              # delay could be Datum.findOne
    console.log offset + ' ' + range

for offset in [1..myRange]
  myWrapper offset, myRange

delay 是 setTimeout 的别名(某种),建议 here

【讨论】:

您能否简要解释一下超时/延迟的必要性?消除延迟会产生相同的输出,并且程序会立即完成。 delay (setTimeout) 只是 Datum.findOne 的替代品,我放在那里是为了测试一个带有回调的简单函数,实际上不需要延迟,如果造成混淆,请见谅【参考方案2】:

这实际上是一个闭包问题而不是范围问题。发生的情况是,当您在 javascript 中定义一个函数时(当然也是 coffeescript),该函数会记住创建它的上下文,包括父作用域中的所有变量。但是所拥有的不是变量的副本,而是这些变量的引用。

来自Datum.findOne 的回调将在您的for 循环完成迭代后被调用。这意味着offset 变量已经增加了。你可以很容易地防止它在Datum.findOne 周围包裹一个匿名函数,如下所示:

for offset in [1..3]
  do ( offset = offset ) ->  
    Datum.findOne  date:  $lte: queryDate.toDate()  , (err, datum) ->
      console.log offset

将变量作为参数传递给函数将创建它的副本。

我相信在循环内定义函数更便于阅读,但如果函数很大,或者循环有很多迭代,实际上最好在别处定义它。

//edit:其实coffeescript会在循环外定义。

您可能想参考这个question 来了解闭包。

【讨论】:

以上是关于Nodejs + Coffeescript 的变量范围的主要内容,如果未能解决你的问题,请参考以下文章

现在啊还不太清楚 nodejs和coffeescript 的关系

coffeescript初体验

关于 CoffeeScript 变量范围的困惑

Angular遇上CoffeeScript - NgComponent封装

如何将 JSON 转换为 CoffeeScript 并写入文件“.coffee”?

如何在 Slim 模板中访问 CoffeeScript 引擎中的实例变量