2012-08-16 18 views
5

Dobra, nie wiem jak określić tytuł tego pytania.Zamknięcie nie zostało przechwycone? - 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" 

Rozumiem, że zmienna jest zdefiniowana pod itemBox zakresu openDir jest tutaj. Ale skoro wskazana linia jest w funkcji lambda, to czy nie powinien on przechwytywać obiektu przywoływanego przez itemBox zakresu nadrzędnego, zamiast otrzymywać zmutowany do ostatniego obiektu, do którego się odwołuje?

Mówiąc jasno, oczekuję, że program obsługi kliknięcia każdego z nich itemBox wykona dla siebie addClass "selected". Ale tak się składa, że ​​itemBox w każdej z procedur obsługi kliknięć zawsze odnosi się do ostatniego elementu.

Mogę łatwo to naprawić, zmieniając miejsce, gdzie zostanie zadeklarowany itemBox. tj zmieniając

for item in data.contents 

do

data.contents.forEach (item) -> 

Ale chciałbym wiedzieć, dlaczego funkcja lambda nie przechwytywać zmiennych aktualną wartość.

+0

Pytanie dotyczy także zmiennej 'item' wymienionej w linii' openDir item.path', nawet jeśli jest ona zdefiniowana w zakresie 'openDir's. –

Odpowiedz

9

Ta pętla:

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

jest nieco zwodnicze, jeśli nie jesteś przyzwyczajony do (Coffee | Java) zakres Script. Scoping rzeczywiście wygląda bardziej jak to:

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

więc istnieje tylko jeden itemBox zmienna i że sama zmienna przyzwyczaja przez każdej iteracji pętli. Obsługa kliknięć zachowuje odniesienie do itemBox, ale nie analizuje zmiennej, dopóki nie zostanie wywołana obsługa kliknięcia, więc wszystkie procedury obsługi zakończą się tą samą wartością itemBox i będzie to wartość itemBox na końcu pętli.

Z fine manual:

Kiedy za pomocą pętli JavaScript do generowania funkcji, to wspólny wstawić opakowanie zamykające w celu zapewnienia, że ​​zmienne pętlowe są zamknięte w ciągu, a wszystkie generowane funkcje nie tylko podziel się ostatecznymi wartościami. CoffeeScript dostarcza słowa kluczowego do, które natychmiast wywołuje przekazaną funkcję, przekazując dowolne argumenty.

Więc można to zrobić:

for item in data.contents 
    do (item) -> 
     # As before... 

, aby otrzymać itemBox zawężona do każdej iteracji pętli indywidualnie.

Korzystanie forEach:

data.contents.forEach (item) -> 

zamiast zwykłej pętli działa, ponieważ jesteś skutecznie stosując funkcję ciała pętli i wszelkie zmienne wewnątrz tej funkcji zostanie zawężona do tej funkcji.

+0

Wiedziałem o części zakresu. Ale o czym wspomniałeś: "Obsługa kliknięć zachowuje odniesienie do' itemBox', ale ** nie analizuje zmiennej dopóki nazwa handlowa nie zostanie nazwana ** ', jest tym, czego nie znałem. Przyjąłem, że odwołanie do obiektu wskazanego przez zmienną zostało zachowane przez moduł obsługi kliknięcia. Dzięki! –

Powiązane problemy