封闭范围不捕捉? - 的CoffeeScript(Closure Scope not capt

2019-06-17 18:25发布

好吧,我不知道如何短语标题为这个问题。

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

data.contents.forEach (item) ->

但是,我想知道为什么lambda函数不捕获变量的当前值。

Answer 1:

这个循环:

for item in data.contents
    itemBox = $ "<div/>", class: "itembox"

是有点欺骗性,如果你不习惯(咖啡| JAVA)脚本范围。 作用域其实看起来更像是这样的:

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范围的单独循环的每个迭代。

使用forEach

data.contents.forEach (item) ->

而不是一个简单的循环的工作,因为你正在有效使用功能的循环体和函数内的任何变量将被作用范围包括该功能。



文章来源: Closure Scope not captured? — Coffeescript