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:
- 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).
- 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.
- 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.
- Las declaraciones de funciones se procesan y los resultados se asignan a las propiedades para esas funciones.
- 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 .
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
@Sam: (Gracias.) Perfecto, sí. Eso es exactamente eso. Buen ejemplo, también. –
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