我很难跟踪这个。
...
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
...
对变量作用域的正确方法是什么,以便它们可以在回调中使用?
答案 0 :(得分:1)
这实际上是一个闭包问题,而不是范围问题。当你在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
将变量作为参数传递给函数将创建它的副本。
我相信定义循环内部的函数对于可读性更好,但是如果函数很大,或者循环有很多迭代,那么实际上更好地定义它。
//编辑:实际上,coffeescript会在循环外定义它。
您可能需要参考此question来阅读闭包。
答案 1 :(得分:0)
使用包装功能应该有效。
# 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