2012-08-16 44 views
5

好吧,我不知道如何爲這個問題標題。未收集關閉範圍? - Coffeescript

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" 

據我所知,可變itemBoxopenDir的範圍在此定義。但是由於指出的行是在lambda函數中,因此不應該在itemBox那裏捕獲父範圍的itemBox引用的對象,而不是突變到它引用的最後一個對象?

說得很清楚,我希望每個itemBox的點擊處理程序自己執行addClass "selected"。但是會發生什麼情況是每個點擊處理程序中的itemBox始終引用最後一個itemBox。

我可以通過更改itemBox被聲明的位置來輕鬆解決此問題。即改變

for item in data.contents 

data.contents.forEach (item) -> 

但我想知道爲什麼lambda函數不捕獲變量的當前值。

+0

該問題也適用於'openDir item.path'行中引用的'item'變量,因爲即使在'openDir'範圍內定義了該變量。 – 2012-08-16 22:44:18

回答

9

這個循環:|腳本範圍,如果你不使用(Java的咖啡)

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

有點欺騙性。作用域其實看起來更像是這樣的:

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) -> 

,而不是一個簡單的循環工作,因爲你有效地使用功能的循環體和函數內的任何變量將被作用範圍包括該功能。

+0

我知道範圍部分。但是你提到的'點擊處理程序保留對'itemBox'的引用,但**不會評估變量,直到點擊處理程序被調用**',這是我不知道的。我曾假定變量所指向的對象的引用由click處理程序保存。謝謝! – 2012-08-16 22:37:48