好吧,我不知道如何表达这个问题的标题。
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
父作用域的而不是突变到它引用的最后一个对象?
明确地说,我期望每个的点击处理程序itemBox
去表演addClass "selected"
对自己。但发生的事情是itemBox
在每个单击处理程序中始终引用最后一个 itemBox。
我可以通过更改 itemBox 的声明位置轻松解决此问题。即改变
for item in data.contents
into
data.contents.forEach (item) ->
但我想知道为什么 lambda 函数不捕获变量的当前值。
这个循环:
for item in data.contents
itemBox = $ "<div/>", class: "itembox"
如果您不习惯 (Coffee|Java)Script 范围,则有些欺骗性。范围实际上看起来更像是这样的:
itemBox = undefined
for item in data.contents
itemBox = $ "<div/>", class: "itembox"
所以只有一个itemBox
变量,并且循环的每次迭代都会使用同一变量。单击处理程序保留对itemBox
但在调用单击处理程序之前不会评估变量,因此所有处理程序最终都会得到相同的结果itemBox
值,这将是itemBox
循环结束时的值。
来自精美手册:
当使用 JavaScript 循环生成函数时,通常会插入闭包包装器以确保循环变量被封闭,并且所有生成的函数不仅仅共享最终值。 CoffeeScript 提供了do
关键字,它立即调用传递的函数,转发任何参数。
所以你可以这样做:
for item in data.contents
do (item) ->
# As before...
得到你的itemBox
范围分别为循环的每次迭代。
Using forEach
:
data.contents.forEach (item) ->
而不是简单的循环可以工作,因为您有效地使用函数作为循环体,并且该函数内的任何变量都将作用于该函数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)