未捕获关闭范围? — 咖啡脚本

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 的引用,但在调用点击处理程序之前不会评估变量”,这是我不知道的。我假设对变量指向的对象的引用由点击处理程序保存。谢谢!

以上是关于未捕获关闭范围? — 咖啡脚本的主要内容,如果未能解决你的问题,请参考以下文章

Jasmine 与咖啡脚本共享规范范围问题

“未捕获(承诺)的DOMException:无法为范围注册ServiceWorker”-脚本资源位于重定向后面,不允许使用

未捕获的 DOMException:无法在“范围”上执行“setStart”:偏移量大于节点的长度

由于未捕获的异常“NSRangeException”而终止应用程序。 [__NSArrayM objectAtIndex:]:索引 33 超出范围 [0 .. 32]'

由于未捕获的异常“RLMException”而终止应用程序,原因:“索引 0 超出范围(必须小于 0)。”迅速

由于未捕获的异常“NSRangeException”而终止应用程序,原因:“*** -[__NSArrayM objectAtIndex:]:索引 0 超出空数组的范围”