未捕获关闭范围?— 咖啡脚本 [英] Closure Scope not captured? — Coffeescript
问题描述
好的,我不知道如何表达这个问题的标题.
Okay, I don't know how to phrase the title for this question.
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
引用的对象,而不是突变为最后一个引用的对象靠它?
I understand that the variable itemBox
is defined under openDir
's scope here. But since the pointed out line is in a lambda function, shouldn't itemBox
there capture the object referenced by itemBox
of the parent scope instead of getting mutated to the last object referenced by it?
明确地说,我希望每个 itemBox
的点击处理程序对自己执行 addClass "selected"
.但是发生的情况是,每个点击处理程序中的 itemBox
总是引用最后一个 itemBox.
To put it clearly, I expect the click handler of each itemBox
to perform addClass "selected"
to itself. But what happens is that itemBox
in each of the click handlers always refer to the last itemBox.
我可以通过更改 itemBox 的声明位置来轻松解决此问题.即改变
I can easily fix this by changing where itemBox gets declared. i.e. changing
for item in data.contents
进入
data.contents.forEach (item) ->
但我想知道为什么 lambda 函数不捕获变量当前值.
But I'd like to know why the lambda function does not capture the variables current value.
推荐答案
这个循环:
for item in data.contents
itemBox = $ "<div/>", class: "itembox"
如果您不习惯 (Coffee|Java)Script 范围,
会有点欺骗性.范围实际上看起来更像这样:
is somewhat deceptive if you're not used to (Coffee|Java)Script scope. The scoping actually looks more like this:
itemBox = undefined
for item in data.contents
itemBox = $ "<div/>", class: "itembox"
所以只有一个 itemBox
变量,并且循环的每次迭代都会使用同一个变量.单击处理程序保留对 itemBox
的引用,但在调用单击处理程序之前不会评估变量,因此所有处理程序最终都具有相同的 itemBox
值,这将是循环结束时的 itemBox
值.
so there is only one itemBox
variable and that same variable gets used by each iteration of the loop. The click handler keeps a reference to itemBox
but doesn't evaluate the variable until the click handler is called so all the handlers end up with the same itemBox
value and that will be the itemBox
value at the end of the loop.
来自精美手册:
当使用 JavaScript 循环生成函数时,通常会插入一个闭包包装器以确保循环变量被封闭,并且所有生成的函数不只是共享最终值.CoffeeScript 提供了 do
关键字,它立即调用传递的函数,转发任何参数.
When using a JavaScript loop to generate functions, it's common to insert a closure wrapper in order to ensure that loop variables are closed over, and all the generated functions don't just share the final values. CoffeeScript provides the
do
keyword, which immediately invokes a passed function, forwarding any arguments.
所以你可以这样做:
for item in data.contents
do (item) ->
# As before...
将您的 itemBox
分别限定为循环的每个迭代.
to get your itemBox
scoped to each iteration of the loop individually.
使用 forEach
:
data.contents.forEach (item) ->
而不是简单的循环起作用,因为您有效地将函数用作循环的主体,并且该函数内的任何变量都将作用于该函数.
instead of a simple loop works because you're effectively using a function as the loop's body and any variables inside that function will be scoped to that function.
这篇关于未捕获关闭范围?— 咖啡脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!