【问题标题】:Variable scope with Nodejs + CoffeescriptNodejs + 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

...

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

【问题讨论】:

    标签: node.js express coffeescript mongoose momentjs


    【解决方案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 来了解闭包。

    【讨论】:

      猜你喜欢
      • 2012-01-20
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 2019-01-10
      • 1970-01-01
      • 1970-01-01
      • 2015-08-20
      相关资源
      最近更新 更多