2011-04-21 8 views
6

vi esta prueba Javascript aquí: http://www.netfxharmonics.com/2008/01/NetFX-Harmonics-JavaScript-Quiz¿Por qué esta variable de ámbito de cierre pierde su valor?

y no pude averiguar este problema:

(function(){ 
    var a = 1; 
    var b = 2; 

    (function() { a = b; var b; })(); 

    console.log('a:'+ a); // => "a:undefined" 
    console.log('b:'+ b); // => "b:2" 
})() 

Sin embargo, si se quita la declaración var b; de la función interna, entonces a == 2 como era de esperar.

¿Por qué sucede esto?

(Puedes jugar con él aquí: http://jsfiddle.net/gnhMZ/)

Respuesta

8

Está sucediendo porque esta función:

(function() { a = b; var b; })(); 

... asigna undefined-a. var takes effect as of the beginning of the scope in which it's written, no donde se encuentra el código paso a paso. Y cuando declaras una variable, su valor inicial es undefined. Por lo que el anterior escrito de manera más explícita, pero con exactamente la misma funcionalidad, se ve así:

(function() { 
    var b = undefined; 
    a = b; 
})(); 

Específicamente, cuando la ejecución entra en un contexto ejecución, estas cosas suceden:

  1. Una detrás de las -scenes objeto variable se crea para el contexto de ejecución y se coloca en la parte superior de la cadena de ámbito (la cadena de objetos variables utilizada para resolver referencias no calificadas).
  2. Las propiedades se crean en ese objeto variable para cada var declarado dentro del contexto, independientemente de dónde se encuentre la instrucción var. El valor inicial de cada variable es undefined. Los inicializadores no se manejan en este punto.
  3. Las propiedades se crean en el objeto variable para cada función declarada (con una declaración de función, no una expresión de función) dentro del contexto, independientemente de dónde esté la declaración de función.
  4. Las declaraciones de funciones se procesan y los resultados se asignan a las propiedades para esas funciones.
  5. La ejecución continúa con la primera línea de código paso a paso en el contexto. Cuando se encuentra una instrucción var con un inicializador, se procesa como una declaración de asignación simple.

El objeto variable es lo que hace que los cierres funcionan, también, por cierto. More here, pero básicamente, cuando se crea una función obtiene una referencia permanente a todos los objetos variables en la cadena de alcance en ese punto. Eso es lo que usa para buscar las variables que cierra. Esto es importante porque un cierre no solo tiene una referencia duradera a las variables que realmente usa, sino a todas las variables en el alcance donde se define, si las usa o no, lo que puede tener implicaciones para el ciclo de vida de esas variables .

+0

Excelente explicación. Otro caso que lo deja en claro sería si tuviéramos '(función() {a = b; var b = 3;})()' como la función interna. Eso sería lo mismo que '(function() {var b; a = b; b = 3;})()' then, right? – Sam

+0

@Sam: (Gracias.) Perfecto, sí. Eso es exactamente eso. Buen ejemplo, también. –

+0

Espera ... ¿esto también significa que si tiene una declaración 'var' ** debajo de ** una función, y luego devuelve esa función, el cierre contendrá esa var? – Sam

1

Una gran explicación pero la respuesta simple es que la variable "a" no está declarada dentro de la función interna. Por lo tanto, se convierte en un alcance global que supera el valor del alcance exterior.

a = "undefined"; // ámbito global

var = 1; // relativo a su alcance

Cuestiones relacionadas