2012-08-16 8 views
5

Okay, ich weiß nicht, wie man den Titel für diese Frage formuliert.Closure Scope nicht erfasst? - 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" 

Ich verstehe, dass die Variable itemBox hier unter openDir ‚s Umfang definiert ist. Aber da die aufgezeigte Linie in einer Lambda-Funktion ist, sollte nicht das itemBox Objekt von itemBox des übergeordneten Bereichs referenziert statt mutiert zu dem letzten Objekt referenziert werden?

Um es klar zu sagen, erwarte ich, dass die Click-Handler von jedem itemBoxaddClass "selected" zu sich selbst durchführen. Aber was passiert, ist, dass sich in jedem Klick-Handler immer auf die letzte itemBox bezieht.

Ich kann das leicht beheben, indem Sie ändern, wo itemBox deklariert wird. das heißt Ändern

for item in data.contents 

in

data.contents.forEach (item) -> 

Aber ich würde gerne wissen, warum die Lambda-Funktion nicht die Variablen aktuellen Wert nicht erfassen.

+0

Die Frage gilt auch für die Variable 'item', die in der Zeile 'openDir item.path' referenziert wird, da auch diese im' openDir'-Bereich definiert wird. –

Antwort

9

Diese Schleife:

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

ist etwas trügerisch, wenn Sie (Kaffee | Java) nicht gewohnt sind Skriptbereich. Die Scoping sieht eigentlich mehr wie folgt aus:

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

so gibt es nur eine itemBox Variable und die gleiche Variable wird von jeder Iteration der Schleife verwendet. Der Click-Handler behält einen Verweis auf itemBox bei, wertet die Variable jedoch erst aus, wenn der Click-Handler aufgerufen wird, so dass alle Handler denselben itemBox-Wert erhalten und der Wert itemBox am Ende der Schleife lautet.

Vom fine manual:

Wenn eine JavaScript-Schleife Funktionen zu generieren, ist es üblich, einen Verschluss-Wrapper einzusetzen, um zu gewährleisten, dass Schleifenvariablen geschlossen über werden, und alle erzeugten Funktionen nicht nur teile die endgültigen Werte. CoffeeScript stellt das Schlüsselwort do zur Verfügung, das sofort eine übergebene Funktion aufruft und alle Argumente weiterleitet.

So könnten Sie dies tun:

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

, um Ihre itemBox individuell an jede Iteration der Schleife scoped.

Mit forEach:

data.contents.forEach (item) -> 

anstelle einer einfachen Schleife funktioniert, weil Sie effektiv zu dieser Funktion sind eine Funktion wie die Schleife des Körpers und alle Variablen innerhalb dieser Funktion scoped werden.

+0

Ich wusste über den Umfang Teil. Aber was Sie erwähnt haben: "Der Click-Handler behält einen Verweis auf" itemBox ", aber ** wertet die Variable erst aus, wenn der Click-Handler" ** "heißt, was ich nicht wusste. Ich hatte angenommen, dass der Verweis auf das Objekt, auf das die Variable verweist, vom Click-Handler beibehalten wurde. Vielen Dank! –

Verwandte Themen