¡Hola!
Te voy a contar un secreto. Los cierres son un concepto difícil. Las personas arrojan palabras como alcance y persistencia, pero no explican realmente a qué se refieren. Al menos en una medida que la persona promedio puede comprender rápidamente.
Esto es tan frecuente que escribí un artículo al respecto: Destruyendo edificios: una guía simple para los cierres de JavaScript, pero ahora te daré la versión condensada.
Lo primero que debe comprender es que las funciones pueden devolver cualquier cosa .
function my_function () {
retorno 1;
}
La función anterior devuelve un número. Ese número es 1.
function my_function () {
devolver "hola";
}
La función anterior devuelve una cadena. Esa cadena es “hola”.
Y así sucesivamente y así sucesivamente. Puede devolver una matriz . Puede devolver un booleano.
La forma de recuperar esos valores de retorno es invocar ( o llamar ) la función declarada. Me gusta esto:
function my_function () {
devolver "hola";
}
var demo_variable = my_function (); // invocar la función usando parens
console.log (demo_variable); // "Hola"
Para desglosar lo anterior:
- Las funciones pueden devolver cualquier cosa
- Para recuperar el valor de retorno de una función, podemos invocarlo y almacenar el valor devuelto en una variable.
Lo siguiente que debe comprender es que cuando digo ” Una función puede devolver cualquier cosa “, esto incluye funciones.
Eso puede ser difícil de entender, así que echemos un vistazo al código para explicar:
function my_function () {
función de retorno () {
};
}
Actualmente esta función devolverá una función vacía. Esto es solo para mostrar la estructura metálica de lo que sucede debajo del capó.
Al igual que las reglas del club de lucha, la primera regla es “Una función puede devolver cualquier cosa ”, y la segunda regla es “Una función puede devolver cualquier cosa ”. ¿Qué quiero decir con eso? Actualmente tenemos una función que devuelve una función:
function my_function () {
función de retorno () {
};
}
También podemos tener una función que devuelva una función … que devuelva cualquier otra cosa .
function my_function () {
función de retorno () {
retorno 1;
};
}
En lo anterior, tenemos una función que devuelve una función, que devuelve un número.
¿Cómo recuperamos la función interna y su número devuelto?
function my_function () {
función de retorno () {
retorno 1;
};
}
var demo_variable = my_function (); // devuelve la función interna.
// la función interna ahora está almacenada en demo_variable
var demo_variable_2 = demo_variable (); // devuelve el 1
console.log (demo_variable_2); // 1
Esto puede ser un poco complejo de ver, pero todo lo que está sucediendo es esto:
- declaramos una función, my_function, que devuelve una función, que devuelve un 1.
- Invocamos my_function, y su valor de retorno se almacena en demo_variable
- demo_variable ahora es una función que devuelve un 1
- Invocamos la función demo_variable, que devuelve un 1, y la almacenamos en demo_variable_2
- registramos demo_variable_2
Si todavía tiene problemas hasta ahora, lea lo anterior nuevamente. Cópielo en jsfiddle o codepen y juegue con él. Es importante que entiendas esto hasta ahora.
Si comprende todo hasta este punto, felicidades, está a punto de aprender cierres.
En cuanto a envolver la cabeza con los cierres, esta es la parte difícil. Vamos a comenzar lentamente de nuevo con una función estándar. ¡Solo que esta vez, vamos a devolver una variable!
function my_function () {
var my_number = 0;
devuelve my_number;
}
Puedes imaginar que esto no cambia nada. Devolvemos la variable my_number, y si tuviéramos que recuperar el valor de la función de esta manera:
var demo_variable = my_function ();
console.log (demo_variable); // 0
Invariablemente ( ¡ja! ) Obtenemos el valor 0.
Si no sabe, el símbolo ++ simplemente agregará 1 a una variable. No estoy tratando de engañarte aquí, pero trato de responder esta pregunta. ¿Cuál será demo_variable si ejecutamos esta función?
function my_function () {
var my_number = 0;
devuelve my_number ++;
}
var demo_variable = my_function ();
Si lo piensa, todo lo que estamos haciendo es establecer la variable my_number en 0, y luego agregarle 1.
Aquí es donde entramos en la persistencia. Puede sonar complicado, pero no lo pienses demasiado. Todo lo que la palabra significa en este contexto es que si invocamos esta función una y otra vez, el valor de retorno no persistiría porque cada invocación de función es su propia instancia. Básicamente vive en su propio pequeño mundo con su propia variable my_number . En código quiero decir esto:
var demo_variable = my_function ();
// lo anterior no tiene correlación con lo siguiente.
// son instancias separadas, mundos separados
// my_number está disponible en ambas funciones
// pero no son lo mismo my_number
var demo_variable_2 = my_function ();
Entonces, ¿cómo podríamos lograr que la variable my_number persista ? Bueno, primero debe comprender esta regla sobre las funciones:
“Todas las funciones se eliminan de la memoria cuando ya no son necesarias o están en uso”.
Esto significa que todas las variables de función (my_number) dejan de existir una vez que la función ha terminado de ejecutarse. Esto significa que tan pronto como el navegador esté seguro de que esta función se haya ejecutado, se eliminará de la memoria.
¿No sería bueno si pudiéramos inyectar un marcador de posición en la función para que el navegador nunca estuviera seguro de que terminó de ejecutarse? Algo como, no sé, ¿una referencia a una función interna?
function my_function () {
var my_number = 0;
función de retorno () {
devuelve my_number ++;
}
}
Lo anterior puede parecer confuso, pero trate de no pensar demasiado. La forma en que esto funciona es la siguiente:
- crear función, my_function, que declara una variable my_number y le da un valor.
- devuelve una función de my_function, que establece my_number en sí mismo + 1, y devuelve my_number.
En la práctica, esto se ve así:
function my_function () {
var my_number = 0;
función de retorno () {
devuelve my_number ++;
}
}
var demo_variable = my_function (); // declara my_number = 0, función de retorno
console.log (demo_variable ()); // invocar demo_variable, devolver my_number ++ (0 + 0)
demo_variable (); // invocar demo_variable, devolver my_number ++ (0 + 1)
demo_variable (); // invocar demo_variable, devolver my_number ++ (1 + 1)
console.log (demo_variable ()); // 3 (devuelve my_number (2 + 1)) le (); // invoca demo_variable, devuelve my_number ++ (2 + 1)
console.log (demo_variable ()); // 4 (devuelve my_number (3 + 1))
Puedes jugar con la demo aquí: Editar violín – JSFiddle
Lo que sucede es que, debido a que demo_variable siempre hace referencia al código dentro de my_function, my_function no se puede eliminar de la memoria. Como my_function no se puede eliminar de la memoria, my_number persiste.
Así es como funcionan los cierres.
Si esta respuesta no lo hace por usted y está buscando una lección mucho más profunda, eche un vistazo al artículo Destrucción de edificios: una guía simple para los cierres de JavaScript: se ha recibido bien y posiblemente pueda eliminar cualquier Más preguntas que pueda tener.
¡Feliz codificación!