El cierre es una dificultad en el lenguaje JavaScript y su característica. Muchas aplicaciones avanzadas dependen de los cierres para implementar. He estado expuesto al concepto de cierres durante mucho tiempo, pero he estado confundido y no he podido entender qué son los cierres de JavaScript y cuáles son útiles. Hoy vi un artículo sobre los cierres de JavaScript (enlace original) en Internet. Fue muy bien explicado. Ahora he entendido completamente que los cierres de JavaScript son algo mágico y el propósito de los cierres. Los escribiré aquí para compartir contigo. ¡Espero que los amigos que no entiendan los cierres de JavaScript puedan entender los cierres después de leerlos! La mayor parte del siguiente contenido proviene del texto original. ¡Agregué algunos comentarios de código, representaciones de operaciones y una pequeña modificación al texto original para una fácil comprensión!
1. El alcance de las variables
Para comprender los cierres, primero debe comprender el alcance variable especial de JavaScript.
En JavaScript, el alcance de las variables se divide en dos tipos: variables globales y variables locales.
En JavaScript, las variables globales se pueden leer directamente dentro de una función.
var n =; // Defina la variable global nfunction f () {alerta ("Acceda a la variable global n, n ="+n); // Acceda a la variable global n} f (); //Resultados de ejecución:
Pero el otro lado no es posible, las variables locales dentro de la función no se pueden leer fuera de la función.
función f () {var n =; // Defina la variable local n} alerta ("Acceda a la variable local n fuera de la función, n ="+n); // acceder a la variable local n fuera de la función, error: n no está definidoResultados de ejecución:
Hay un lugar para tener en cuenta aquí. Al declarar las variables internamente, debe usar el comando VAR. Si no, ¡en realidad es una variable global declarada!
función f () {n =;} f (); alert ("n no se declara con var dentro de la función f1, en este momento n es una variable global, /r /n prueba: n ="+n+", el resultado de Window.n == n es:"+(Window.n == n));Resultados de ejecución:
2. ¿Cómo leer las variables locales desde el exterior?
Por varias razones, a veces necesitamos obtener variables locales dentro de la función. Sin embargo, como se mencionó anteriormente, en circunstancias normales, esto no se puede hacer y solo se puede lograr a través de soluciones.
Eso es definir otra función dentro de la función.
función f () {var n =; // Variable local n dentro de la función F // Definir una función F Función f () {// Dentro de la función F, alerta (n); //}}En el código anterior, la función F2 se incluye dentro de la función F1, y todas las variables locales dentro de F1 son visibles para F2. Pero al revés no es posible. Las variables locales dentro de F2 son invisibles para F1. Esta es la estructura de "alcance de la cadena" exclusiva del lenguaje JavaScript. Los objetos secundarios buscarán el nivel hacia arriba por nivel para todas las variables de los objetos principales. Por lo tanto, todas las variables del objeto principal son visibles para el objeto infantil, de lo contrario no es cierto. Dado que F2 puede leer las variables locales en F1, siempre que se use F2 como valor de retorno, ¿no podemos leer sus variables internas fuera de F1? Algunas personas pueden tener preguntas. F2 es una función, ¿cómo se puede devolver como el valor de retorno de la función F1? De hecho, está bien. El nombre de la función en JavaScript en sí es una variable, por lo que la función también se puede usar como una variable normal. Es decir, no solo se puede pasar una función a otra función como los parámetros de pasar, sino que también se puede devolver una función como el valor de retorno de otra función.
función f () {var n =; // Variable local N // F Función declarada dentro de la función f () {alerta (n); } return f; // use la función f como el valor de retorno de la función f} var result = f (); // El valor de retorno después de que se llama F es una función F, y el resultado es F de la función F result (); // 999, llame a la función F2Resultados de ejecución:
3. El concepto de cierre
La función F2 en la sección anterior del código es el cierre. La definición de "cierre" en varios documentos profesionales es muy abstracta. Por ejemplo, hay una definición de cierre: "Un cierre de JavaScript es una variable que obtiene de la función o alcance de nivel anterior en otro alcance, y estas variables no se destruirán a medida que se complete la ejecución de la función de nivel anterior". Es difícil para mí comprender tal definición de cierre. Entiendo que un cierre es una función que puede leer variables dentro de otras funciones. Dado que en el lenguaje JavaScript, solo las subfunciones dentro de las funciones pueden leer variables locales, los cierres pueden entenderse simplemente como "funciones definidas dentro de una función". Entonces, en esencia, un cierre es un puente que conecta el interior y el exterior de la función.
4. El propósito del cierre
Los cierres se pueden usar en muchos lugares. Tiene dos mayores usos, uno es que las variables dentro de la función se pueden leer como se mencionó anteriormente, y la otra es que los valores de estas variables siempre se mantienen en la memoria.
¿Cómo entender esta oración? Consulte el código a continuación.
función f () {var n =; // nadd es una variable global que no se declara usando var. Esta variable ahora apunta a una función anónima declarada dentro de la función F nadd = function () {n+=} function f () {alert (n); } return f; } var de resultado = f (); // El resultado es la función F result (); // La primera llamada a la función de resultado nadd (); // nadd representa una función anónima declarada dentro de la función F, nadd () es el resultado de la función anónima (); // la segunda llamada a la función de resultado 1000 1000Resultados de ejecución:
En este código, el resultado es en realidad la función de cierre F2. Se ejecuta dos veces en total, el primer valor es 999 y el segundo valor es 1000. Esto demuestra que la variable local N en la función F1 se ha mantenido en la memoria y no se borra automáticamente después de que se llama a F1.
¿Por qué está sucediendo esto? La razón es que F1 es la función principal de F2, y F2 se asigna a una variable global, que hace que F2 esté siempre en la memoria, y la existencia de F2 depende de F1. Por lo tanto, F1 siempre está en la memoria y no será reciclado por el mecanismo de recolección de basura después de que termine la llamada.
Otro punto notable en este código es que la línea "nadd = function () {n+= 1}" se usa primero antes de NADD, por lo que NADD es una variable global, no una variable local. En segundo lugar, el valor de NADD es una función anónima, y esta función anónima en sí misma también es un cierre, por lo que NADD es equivalente a un setter, que puede operar en variables locales dentro de la función fuera de la función.
5. Notas sobre el uso de cierres
1) Dado que los cierres causarán que todas las variables en la función se almacenen en la memoria, y el consumo de memoria es muy grande, los cierres no se pueden abusar, de lo contrario causará problemas de rendimiento de la página web y puede conducir a la fuga de memoria en IE. La solución es eliminar todas las variables locales que no se usan antes de salir de la función.
2) El cierre cambiará el valor de la variable dentro de la función principal fuera de la función principal. Por lo tanto, si usa la función principal como objeto, use el cierre como método público y use la variable interna como propiedad privada, tenga cuidado de no cambiar el valor de la variable interna de la función principal a voluntad.
6. Preguntas de pensamiento
Si puede comprender los resultados de la ejecución de las siguientes dos piezas de código, debe considerarse comprender el mecanismo de ejecución del cierre.
Fragmento de código 1:
var name = "la ventana"; var objeto = {nombre: "mi objeto", getNameFunc: function () {return function () {return this.name; }; }}; alert (objeto.getNameFunc () () ());Resultados de ejecución:
Fragmento de código dos:
var name = "la ventana"; var objeto = {nombre: "mi objeto", getNameFunc: function () {var that = this; Función de retorno () {return that.name; }; }}; alert (object.getNameFunc () ());Resultados de ejecución:
Los siguientes comentarios se agregan al código para analizar los resultados en ejecución de los dos fragmentos de código anteriores:
Fragmento de código 1:
El análisis es el siguiente:
/*En JavaScript, los objetos globales de JavaScript, las funciones globales y las variables globales que declaramos se convertirán automáticamente en los miembros del objeto de la ventana. Las variables globales son propiedades de los objetos de la ventana. Las funciones globales son métodos de objetos de ventana. */var name = "The Window"; // declare un nombre de variable global, y en este momento el nombre de la variable global se convertirá automáticamente en un atributo del objeto de la ventana // prueba: alerta ("window.name:"+window.name); // puede acceder al nombre en el formulario de window.name (nombre de objeto. Atributo de atributo), luego se convierte en que el nombre de la variable global se convertirá en un atributo de la ventana de la ventana de la ventana de la ventana. El objeto de objeto variable global se convertirá automáticamente en un atributo del objeto de la ventana var objeto = {nombre: "mi objeto", // nombre de atributo del objeto getNameFunc: function () {// getNameFunc Función de objeto objeto // El valor de retorno del método getNameFunc del objeto objeto es una función anónima function () {// en este momento, qué objeto se refiere al objeto de la ventana, qué objeto de objeto se ubica, lo que llama el objeto de la ventana, qué es el objeto de la ventana. que objeto. // Demuestre que esto en la función anónima representa un objeto de ventana en lugar de un ObjectAnt ("este == El resultado del objeto es:"+(este == objeto)); alerta ("this == La ventana del resultado es:"+(this == Window)); devuelve this.name; // Dado que esto representa un objeto de ventana, entonces este.Name accede naturalmente al nombre del objeto de la ventana "la ventana"}; }}; // Prueba: el objeto global del objeto es un atributo de la alerta del objeto de la ventana ("Window.object:"+Window.object); alert ("Window.object.name:"+Window.object.name);/*Después de llamar al método GetNameFunc, se devuelve un método anónimo. En este momento, RETFN representa un método anónimo. Ahora es equivalente a darle al método anónimo un nombre Retfn. En este momento, la función RETFN se convierte automáticamente en una función del objeto de la ventana*/var retfn = object.getNameFunc (); alert (retfn ()); // llamando al método anónimo devuelto, entonces, ¿quién llama a este método anónimo? Es un objeto de ventana // prueba: la función RetFn es una función de la alerta de objeto de ventana ("window.retfn ():"+window.retfn ()); // Puede llamar al método Retfn en forma de window.retfn () (nombre de objeto. Nombre del método)Fragmento de código dos:
El análisis es el siguiente:
var name = "The Window"; // Global Variable Name // Global Object ObjectVar Object = {name: "Mi objeto", getNameFunc: function () {/*¿Qué objeto representa esto en este momento? Esto representa el objeto objeto. ¿Qué objeto llama a la función donde se encuentra esto? Esto se refiere a qué objeto se ha ejecutado que = esto, y eso también representa el objeto objeto*/var que = this; // que es una variable local declarada en la función getNameFunc // demuestra que esto en la función getNameFunc representa el objeto objeto en lugar de WindowAlert ("este == Object Result es:"+(este == Object)); alerta ("this == La ventana, el resultado es:"+(this == Window)); // Demuestre que representa la alerta del objeto del objeto ("que el resultado del objeto == es:"+(que == objeto)); Función de retorno () {/*Esa es una variable local declarada en la función getNameFunc. En circunstancias normales, después de que se completa la llamada de función GetNameFunc, la variable local que será reciclada por el GC de JavaScript, liberando el espacio de memoria ocupado por la variable local que, pero ahora eso puede usarse normalmente y no se ha reciclado. La razón es que GetNameFunc es la función principal de la función anónima. Después de que se llama a la función GetNameFunc, la función anónima se devolverá y asignará a una RETFN de variable global, lo que hace que la función anónima esté siempre en la memoria, y la existencia de la función anónima depende de la función GetNameFunc. Por lo tanto, la función GetNameFunc siempre está en la memoria y no será reciclada por el mecanismo de recolección de basura después de que se termine la llamada. Dado que la función GetNameFunc siempre está en la memoria, esa variable local declarada dentro de la función GetNameFunc siempre existirá en la memoria. Como existe, por supuesto que puede continuar siendo utilizándose. */return that.name; // que representa el objeto objeto, de modo que el nombre de nombre accede naturalmente al nombre del objeto "mi objeto"}; }}; var retfn = object.getNameFunc (); // Después de llamar al método GetNameFunc, se devuelve un método anónimo. En este momento, RETFN representa un método anónimo, que ahora es equivalente a dar al método anónimo que un nombre es Retfn Alert (retfn ());Finalmente, también adjunté un ejemplo que escribí cuando aprendí los cierres de JavaScript antes:
<script type="text/javascript">function A(){var i = ;//Declare the local variable i inside function A/Declare the subfunction bfunction b(){alert("i = "+(++i));//Access the local variable i declared inside function A within function A} return b;//Return the address of the function b}/*After executing var c = After A(), the variable c actually points to la función b. b. La variable I se usa. Después de ejecutar c (), aparecerá una ventana para mostrar el valor de I (la primera vez) y este código en realidad crea un cierre, porque la variable C fuera de la función A se refiere a la función B interna A. Es decir: cuando la función interna B de la función A está referenciada por una variable externa de la función A, se crea un llamado cierre de "cierre". Después de que A se haya ejecutado y devuelto, el cierre hace que el mecanismo de recolección de basura de JavaScript GC no reciclará los recursos ocupados por A, porque la ejecución de la función interna B de A necesita confiar en la variable en A */A (); // Definitivamente habrá espacio en la memoria. Después de ejecutar a (), GC reciclará el espacio de memoria asignado para i var c = a (); // Este uso, GC no tratará a i como basura y c (); // equivalente a llamar b (), el resultado es: i = c (); // El resultado es: i = c (); // El resultado es: i = c (); // el resultado es: i = <</<script>Resultados de ejecución:
El contenido anterior es la explicación detallada del código de cierre de JavaScript (cierre) de los puntos de conocimiento de JavaScript resumidos (16) introducidos por el editor. ¡Espero que sea útil para todos!