好吧,我不知道该怎么表达这个问题的标题。
openDir = (path) ->
socket.emit "get_metadata", path, (data) ->
columnBox = $ "<div/>", class: "columnbox"
for item in data.contents
itemBox = $ "<div/>", class: "itembox"
itemBox.click ->
columnBox_inner.children().removeClass "selected"
itemBox.addClass "selected" # <<<--- Over here
openDir item.path
columnBox.append itemBox
columnBox.appendTo "#columnscontainer"
我知道变量
itemBox
是在这里的openDir
范围下定义的。但是,由于所指出的行在lambda函数中,难道不应该捕获父作用域的itemBox
引用的对象,而不是将其变异为它引用的最后一个对象吗?为了清楚地说明这一点,我希望每个
itemBox
的click处理程序对自己执行itemBox
。但实际情况是,每个单击处理程序中的addClass "selected"
总是引用最后一个itembox。通过改变itembox的声明位置,我可以很容易地解决这个问题。即改变
for item in data.contents
进入之内
data.contents.forEach (item) ->
但我想知道为什么lambda函数不捕获变量的当前值。
最佳答案
此循环:
for item in data.contents
itemBox = $ "<div/>", class: "itembox"
如果您不习惯(coffee java)脚本范围,则会有点欺骗性。范围界定实际上更像这样:
itemBox = undefined
for item in data.contents
itemBox = $ "<div/>", class: "itembox"
所以只有一个
itemBox
变量,循环的每次迭代都使用同一个变量。click处理程序保留对itemBox
的引用,但在调用click处理程序之前不会计算该变量,因此所有处理程序都以相同的itemBox
值结束,这将是循环结束时的itemBox
值。从fine manual开始:
当使用javascript循环生成函数时,通常会插入一个闭包,以确保循环变量是闭合的,并且所有生成的函数不仅仅共享最终值。coffeescript提供
do
关键字,该关键字立即调用传递的函数,并转发任何参数。所以你可以这样做:
for item in data.contents
do (item) ->
# As before...
将
itemBox
的作用域分别设置为循环的每个迭代。使用
forEach
:data.contents.forEach (item) ->
而不是简单的循环,因为您有效地使用了函数作为循环的主体,并且该函数中的任何变量都将作用于该函数。