Esto no es ni un problema alcance ni tampoco es un problema de cierre. El problema está en entender entre declaraciones y expresiones.
código JavaScript, ya que incluso la primera versión de Netscape de JavaScript y Microsoft primera copia de la misma, se procesa en dos fases:
Fase 1: Elaboración - en esta fase el código se compila en un árbol sintáctico (y código de bytes o binario dependiendo del motor).
Fase 2: ejecución: se interpreta el código analizado.
La sintaxis para la declaración de la función es:
function name (arguments) {code}
Los argumentos son, por supuesto, opcional (código es opcional también, pero ¿cuál es el punto de eso?).
Pero JavaScript también le permite crear funciones usando expresiones. La sintaxis de las expresiones de funciones es similar a las declaraciones de funciones, excepto que están escritas en el contexto de expresión. Y las expresiones son:
- Cualquier cosa a la derecha de un signo
=
(o :
de objetos literales).
- Cualquier cosa entre paréntesis
()
.
- Parámetros para las funciones (esto ya está cubierto por 2).
Expresiones a diferencia de declaraciones se procesan en la fase de ejecución en lugar de la fase de compilación. Y debido a esto, el orden de las expresiones es importante.
Por lo tanto, para aclarar:
// 1
(function() {
setTimeout(someFunction, 10);
var someFunction = function() { alert('here1'); };
})();
Fase 1: compilación. El compilador ve que la variable someFunction
se define para que la cree. Por defecto, todas las variables creadas tienen el valor de indefinido. Tenga en cuenta que el compilador no puede asignar valores aún en este punto porque los valores pueden necesitar que el intérprete ejecute algún código para devolver un valor para asignar. Y en este momento todavía no estamos ejecutando el código.
Fase 2: ejecución. El intérprete ve que quiere pasar la variable someFunction
a setTimeout. Y así es. Lamentablemente, el valor actual de someFunction
no está definido.
// 2
(function() {
setTimeout(someFunction, 10);
function someFunction() { alert('here2'); }
})();
Fase 1: compilación. El compilador ve que estás declarando una función con el nombre algunaFunción y así la crea.
Fase 2: El intérprete ve que quiere pasar someFunction
al setTimeout. Y así es. El valor actual de someFunction
es su declaración de función compilada.
// 3
(function() {
setTimeout(function() { someFunction(); }, 10);
var someFunction = function() { alert('here3'); };
})();
Fase 1: compilación. El compilador ve que ha declarado una variable someFunction
y la crea. Como antes, su valor no está definido.
Fase 2: ejecución. El intérprete pasa una función anónima a setTimeout para que se ejecute más tarde. En esta función, ve que está usando la variable someFunction
, por lo que crea un cierre a la variable. En este punto, el valor de someFunction
aún no está definido. Luego ve que asigna una función al someFunction
. En este punto, el valor de someFunction
ya no está indefinido. 1/100 de segundo después, se activan los setTimeout y se llama a algunaFunción. Como su valor ya no está indefinido, funciona.
Caso 4 es realmente otra versión del caso 2 con un poco de caso 3 tirado. En el punto someFunction
se pasa a SetTimeOut ya existe debido a que se declaró.
aclaración adicional:
Usted puede preguntarse por qué setTimeout(someFunction, 10)
no crea un cierre entre la copia local de algunaFuncion y la aprobada para setTimeout. La respuesta a esto es que los argumentos de función en JavaScript siempre son siempre pasados por valor si son números o cadenas o como referencia para todo lo demás. Así que setTimeout en realidad no obtiene la variable que alguna función le pasó (lo que significaría que se está creando un cierre) sino que solo obtiene el objeto al que se refiere alguna función (que en este caso es una función).Este es el mecanismo más utilizado en JavaScript para romper cierres (por ejemplo, en bucles).
Esa fue una gran respuesta. –
Esto probablemente sea una falta de comprensión de los cierres, pero siempre lo consideré como el acceso a un alcance, no como la creación de algo entre un alcance y otro. También pensé que estaba en el nivel de alcance, no en el nivel variable. ¿Le importaría elaborar un poco más sobre eso, o señalarme en la dirección de algo que pueda leer? De nuevo, gran respuesta, ojalá pudiera votarlo dos veces. –
Esta respuesta me hace desear poder votar varias veces en la misma respuesta. Verdaderamente una gran respuesta. Gracias – ArtBIT