Los cierres son una característica importante en JavaScript, y su función más grande es guardar información durante la operación de la función. En JavaScript, muchas características de los cierres se derivan de la cadena de alcance durante las llamadas de función.
Cadena de alcance de la función Llamar objetos y variables
Para cada llamada de función en JavaScript, JavaScript creará un objeto local para almacenar las variables locales definidas en la función; Si hay una función anidada dentro de la función, JavaScript definirá un objeto local anidado en el objeto local ya definido. Para una función, hay tantas capas de definiciones de funciones anidadas como hay, tantas capas de objetos locales anidados como hay. Este objeto local se llama "objeto de llamada de función" ("objeto de llamada" en Ecmascript 3, y se renombró "Registro de entorno declarativo" en Ecmascript 5, pero personalmente creo que el nombre en Ecmascript 3 es más fácil de entender). Las siguientes llamadas de función se utilizan como ejemplo:
La copia del código es la siguiente:
función f (x) {
var a = 10;
devolver a*x;
}
console.log (f (6)); // 60
En este simple ejemplo, cuando se llama la función f (), JavaScript creará un objeto de llamada de la función f () (llamándolo F_invokeObj). Hay dos propiedades dentro del objeto f_invokeobj: a y x; Cuando se ejecuta f (), el valor A es 10 y el valor x es 6, por lo que el resultado final de retorno es 60. La ilustración es la siguiente:
Cuando hay funciones de anidación, JavaScript creará múltiples objetos de llamadas de funciones:
La copia del código es la siguiente:
función f (x) {
var a = 10;
devolver a*g (x);
función g (b) {
regreso b*b;
}
}
console.log (f (6)); // 360
En este ejemplo, al llamar a la función f (), JavaScript creará un objeto de llamada de la función f () (f_invokeBJ), que tiene dos atributos a y x, y el valor a es 10 y el valor x es 6; Al ejecutar f (), JavaScript analizará y definirá la función g () en la función f () y creará un objeto de llamada de g () (g_invokeObj), que tiene un atributo B, y el valor B es el mismo que el parámetro X aprobado, por lo que el resultado de retorno final es 360. La ilustración es la siguiente:
Como puede ver, el objeto de llamada de función forma una cadena. Cuando la función integrada G () se está ejecutando y necesita obtener el valor variable, comenzará a buscar desde el objeto de llamada de función más reciente. Si no se puede buscar, busque en un objeto de llamada adicional a lo largo de la cadena de objeto de llamada de función, que es la llamada "cadena de alcance de variables". Si la misma variable aparece en los dos objetos de llamada de función, la función tomará el valor variable en el objeto de llamada más cercano a él:
La copia del código es la siguiente:
función f (x) {
var a = 10;
devolver a*g (x);
función g (b) {
var a = 1;
regresar b*b*a;
}
}
console.log (f (6)); // 360, no 3600
En el ejemplo anterior, la variable A tiene diferentes valores en el objeto llamado (g_invokeobj) de la función g () y el objeto llamado (f_invokeobj) de la función f (). Al ejecutar la función g (), el valor de un usado dentro de la función g () es 1, mientras que el valor de un usado fuera de la función g () es 1. La cadena de objeto de llamada de función en este momento es el siguiente:
¿Qué es un cierre?
Todas las funciones en JavaScript son objetos, y al definir las funciones, se generará una cadena correspondiente de objetos de llamadas de función. Una definición de función corresponde a una cadena de objetos de llamadas de función. Mientras exista el objeto de función, existe el objeto de llamada de función correspondiente; Una vez que ya no se usa una función, el objeto de llamada de función correspondiente se recolectará basura; y esta combinación del objeto de función y el objeto de llamada de la cadena de función se llama "cierre". En los ejemplos anteriores de la función f () y la función g (), hay dos cierres: el objeto de función f () y el objeto f_invokeobj forma un cierre, y el objeto de función g () y el g_invokeobj-f_invokeobj cadena de la cadena de objeto forman el segundo cierre. Cuando se ejecuta la función g (), ya que la función g () ya no se usa, el cierre g () se recolecta basura; Luego, cuando se ejecuta la función f (), el cierre f () también se recolecta basura por la misma razón.
A partir de la definición de cierre, podemos sacar una conclusión: todas las funciones de JavaScript son cierres después de la definición porque todas las funciones son objetos, y todas las funciones también tienen sus cadenas de objetos de llamada correspondientes después de la ejecución.
Sin embargo, lo que hace que los cierres funcionen realmente es el caso de las funciones anidadas. Dado que la función incrustada se define solo cuando la función externa se está ejecutando, el valor variable almacenado en el cierre de la función incrustada (especialmente el valor variable local de la función externa) es el valor durante esta ejecución. Mientras todavía exista el objeto de función integrada, su cierre todavía existe (el valor variable en el cierre no cambiará ninguno), lo que alcanza el propósito de guardar la información del proceso de ejecución de la función. Considere el siguiente ejemplo:
La copia del código es la siguiente:
var a = "exterior";
función f () {
var a = "interior";
función g () {return a;}
regresar G;
}
resultado var = f ();
console.log (resultado ()); // dentro
En este ejemplo, cuando se ejecuta la función F (), se define la función G () y se crea un cierre de la función G (). El cierre G () contiene la cadena de objetos G_invokeOBJ-F_InvoKeOBJ, por lo que se guarda el valor de la variable A durante la ejecución de la función F (). Cuando se ejecuta la instrucción console.log (), el cierre g () todavía existe porque el objeto de función g todavía existe; Al ejecutar este objeto de función G aún existente, JavaScript usará el cierre G () aún existente y obtendrá el valor de la variable A ("interior") de él.