未捕获关闭范围? — 咖啡脚本
Posted
技术标签:
【中文标题】未捕获关闭范围? — 咖啡脚本【英文标题】:Closure Scope not captured? — Coffeescript 【发布时间】:2012-08-13 08:05:20 【问题描述】:好的,我不知道如何表达这个问题的标题。
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 函数不捕获变量当前值。
【问题讨论】:
这个问题也适用于openDir item.path
行中引用的item
变量,因为即使它是在openDir
的范围中定义的。
【参考方案1】:
这个循环:
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
末尾的值循环。
来自fine manual:
当使用 javascript 循环生成函数时,通常会插入一个闭包包装器以确保循环变量被封闭,并且所有生成的函数不只是共享最终值。 CoffeeScript 提供了
do
关键字,它立即调用传递的函数,转发任何参数。
所以你可以这样做:
for item in data.contents
do (item) ->
# As before...
将您的 itemBox
分别限定为循环的每次迭代。
使用forEach
:
data.contents.forEach (item) ->
而不是简单的循环起作用,因为您有效地将函数用作循环的主体,并且该函数内的任何变量都将作用于该函数。
【讨论】:
我知道范围部分。但是您提到的“点击处理程序保留对itemBox
的引用,但在调用点击处理程序之前不会评估变量”,这是我不知道的。我假设对变量指向的对象的引用由点击处理程序保存。谢谢!以上是关于未捕获关闭范围? — 咖啡脚本的主要内容,如果未能解决你的问题,请参考以下文章
“未捕获(承诺)的DOMException:无法为范围注册ServiceWorker”-脚本资源位于重定向后面,不允许使用
未捕获的 DOMException:无法在“范围”上执行“setStart”:偏移量大于节点的长度
由于未捕获的异常“NSRangeException”而终止应用程序。 [__NSArrayM objectAtIndex:]:索引 33 超出范围 [0 .. 32]'
由于未捕获的异常“RLMException”而终止应用程序,原因:“索引 0 超出范围(必须小于 0)。”迅速
由于未捕获的异常“NSRangeException”而终止应用程序,原因:“*** -[__NSArrayM objectAtIndex:]:索引 0 超出空数组的范围”