2012-08-16 9 views
5

De acuerdo, no sé cómo expresar el título para esta pregunta.Cierre ¿Alcance no capturado? - 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" 

entiendo que la variable itemBox se define en el ámbito openDir 's aquí. Pero dado que la línea señalada está en una función lambda, ¿no debería itemBox capturar el objeto al que hace referencia el itemBox del ámbito principal en lugar de mutar al último objeto al que hace referencia?

Para ponerlo en claro, espero que el manejador de clics de cada itemBox realice consigo mismo. Pero lo que sucede es que itemBox en cada uno de los manejadores de clics siempre se refieren al último elementoBox.

Puedo solucionar esto fácilmente cambiando donde itemBox se declara. es decir, el cambio de

for item in data.contents 

en

data.contents.forEach (item) -> 

pero me gustaría saber por qué la función lambda no capta las variables valor actual.

+0

La pregunta también se aplica a la variable 'item' referenciada en la línea' openDir item.path' como incluso eso se define en el ámbito 'openDir'. –

Respuesta

9

Este bucle:

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

es un tanto engañoso si no estás acostumbrado a (café | Java) ámbito de script. La determinación del alcance realidad se parece más a esto:

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

tan sólo hay una itemBox variable y esa misma variable es utilizada por cada iteración del bucle. El controlador de clics mantiene una referencia a itemBox pero no evalúa la variable hasta que se llame al controlador de clics para que todos los controladores terminen con el mismo valor itemBox y ese será el valor itemBox al final del bucle.

Desde el fine manual:

Cuando se utiliza un bucle JavaScript para generar funciones, es común para insertar un envoltorio de cierre con el fin de asegurar que las variables de bucle se cerraron sobre, y todas las funciones generadas no lo hacen solo comparte los valores finales. CoffeeScript proporciona la palabra clave do, que invoca de inmediato una función aprobada, reenviando cualquier argumento.

Por lo que podría hacer esto:

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

para obtener su itemBox con ámbito de cada iteración del bucle de forma individual.

Usando forEach:

data.contents.forEach (item) -> 

en lugar de un simple bucle funciona porque usted está efectivamente utilizando una función como el cuerpo del bucle y las variables dentro de esa función será de ámbito a esa función.

+0

Sabía sobre la parte del alcance. Pero lo que mencionaste, 'El manejador de clics guarda una referencia a 'itemBox' pero ** no evalúa la variable hasta que se llame al manejador de clics **', es lo que yo no sabía. Supuse que el manejador de clics mantenía la referencia al objeto al que apuntaba la variable. ¡Gracias! –

Cuestiones relacionadas