2011-11-21 12 views
6

Soy un desarrollador de C# y estoy acostumbrado a la forma en que los cierres funcionan en C#. Actualmente tengo para trabajar con funciones javascript anónimos y experimentar un problema con el siguiente fragmento:Acceso a una variable entera copiada en javascript método anónimo

function ClosureTest() { 
    var funcArray = new Array(); 

    var i = 0; 
    while (i < 2) { 
     var contextCopy = i; 

     funcArray[i] = function() { alert(contextCopy); return false; }; 

     i++; 
    } 

    funcArray[0](); 
    funcArray[1](); 
} 

espero que la primera llamada a funcArray() decir 0 y el segundo para decir 1. Sin embargo, ambos dicen 1. ¿Cómo es eso posible?

Escribiendo var contextCopy = i Me aseguro de crear una copia de la variable i. Luego, en cada iteración while, creo un puntero de función completamente nuevo. Cada función se refiere a su propia copia de i, que es contextCopy. Sin embargo, ambas funciones creadas por alguna razón se refieren a la misma variable contextCopy.

¿Cómo funciona esto en javascript?

+0

¿Hay alguna razón por la que no esté utilizando un bucle 'for'? – zzzzBov

+1

no, no ;-) – TwinHabit

Respuesta

11

JavaScript tiene cierres léxicos, no cierres de bloque. Aunque está asignando i a contextCopy, contextCopy es, en sí mismo, un miembro léxico de ClosureTest (que es diferente de C#, donde {} le da un nuevo bloque de ámbito). Pruebe esto:

while (i < 2) { 
    funcArray[i] = (function(value) { 
     return function(){ alert(value); return false; } 
    })(i); 
    i++; 
} 
+0

Gracias, por este ejemplo de trabajo. Después de estas explicaciones presentadas aquí, está claro para mí, por qué mi intento inicial no funciona. – TwinHabit

7

Las llaves ({}) en JavaScript no capturan las variables como lo hacen en C#.

Solo los cierres (funciones) introducen nuevo alcance y capturan variables.

var i = 0; 
while (i < 2) { 
    var contextCopy = i; 
    ... 
} 

es en realidad interpretarse como:

var i, contextCopy; 
i = 0; 
while (i < 2) { 
    contextCopy = i; 
    ... 
} 

Para obtener una copia de la variable, tendrá que ajustar el código con un cierre:

var i; 
i = 0; 
while (i < 2) { 
    (function (contextCopy) { 
    ... 
    }(i)); 
} 
+1

+1 para señalar el alzamiento de la variable contextCopy (no fue tan claro como en mi respuesta) – Matt

+0

muchas gracias por la aclaración – TwinHabit

0

Usted no lo hace crea una copia de la variable i. En cambio, usted hace que esta variable dependa del GC de los cierres que la usan. Significa que cuando el ciclo while sale, la variable i continúa viviendo en su último estado (1) y ambos cierres hacen referencia a ella.

Otra forma de expresarlo: cerrar una variable no la copia en su cierre (no tendría mucho sentido para los objetos), simplemente hace que su cierre haga referencia a la variable y garantiza que esta variable no reciba GC hasta que se cierre.

Cuestiones relacionadas