Cierres en JavaScript | audacia
POSEE cierre se refiere a la combinación de una función y el entorno léxico en el que se declaró esa función. Cada vez que se define una función, se crea un cierre para esa función.
Pero cuando se trata del desarrollo diario, ¿qué significa esto realmente? ¿Cómo se ve un cierre y cómo podemos aprovecharlo mejor en JavaScript?
Para que podamos ver el valor y el impacto de los cierres en el código que escribimos, primero echemos un vistazo a alcance.
Contenido
Alcance.
Cuando se ejecuta una función en JavaScript, crea un nuevo ámbito de tiempo de ejecución. El alcance del tiempo de ejecución describe el conjunto de variables (es decir, identificadores) disponibles para el uso de esa función. Este conjunto de variables incluye:
- Los propios argumentos de la función.
- Variables locales declaradas dentro de la función sí mismo
- Variables del alcance de su función principal
- Variables globales
Considere el siguiente ejemplo:
// Global variable
const a = "a";
function parent() {
// Variable in the parent() function's scope
const b = "b";
function child() {
// Local variable declared in the child() function
const c = "c";
}
}
En el ejemplo anterior, utilice el child()
función tiene acceso a todos a
,b
y c
variables Es decir, estas variables están en el child()
alcance de la función. Es más: si el parent()
la función aceptó cualquier argumento, está anidada child()
la función sería además tener acceso a esos argumentos.
Ahora la pregunta es: ¿cómo es posible todo esto? ¿Cómo funciona realmente el motor de JavaScript? acceso estas variables?
La cadena de alcance.
Bajo el capó, cada vez que su código intente acceder a una variable durante una llamada de función, el motor de JavaScript siempre comenzará buscando dentro de las propias variables locales de la función. Si no se encuentra la variable, la búsqueda continuará buscando lo que se llama el cadena de alcance.
En el siguiente ejemplo, cuando one()
se llama, todas las demás funciones anidadas también se llamarán (hasta three()
):
function one() {
const greeting = "hello";
two();
function two() {
three();
function three() {
console.log(greeting);
}
}
}
one(); // "hello"
Puede visualizar la cadena de alcance moviéndose «hacia afuera» comenzando en el nivel más interno: desde three()
a two()
a one()
, y finalmente a la ventana/objeto global. De esta manera, la función three()
tendrá acceso a cualquier variable y función «por encima» de él (es decir, las de two()
y one()
), así como cualquier variable global definida fuera de one()
. Como tal, cuando three()
accesos greeting
a través de su cadena de ámbito, se imprime «hola» en la consola.
Ahora que hemos visto lo que constituye el alcance de una función, veamos cómo podemos usarlo para nuestro beneficio en el código que escribimos.
Las funciones conservan su alcance.
La búsqueda de identificadores y la cadena de alcance son herramientas poderosas para que una función acceda a los identificadores en el código. De hecho, le permiten hacer algo realmente interesante: crear una función ahora, empaquetarla con algunas variables y guardarla para ejecutarla más tarde.
Considera el remember()
función a continuación:
function remember(number) {
return function () {
return number;
};
}
const returnedFunction = remember(5);
console.log(returnedFunction()); // 5
Cuando el motor de JavaScript entra remember()
, crea un nuevo ámbito de ejecución que apunta al ámbito de tiempo de ejecución anterior. Este nuevo alcance incluye una referencia a la number
parámetro. Cuando el motor llega a la función interna, adjunta un enlace al ámbito de ejecución actual.
Este proceso de una función que conserva el acceso a su alcance se denomina cierre. En este ejemplo, la función interna «se cierra» number
. Dado que un cierre puede capturar cualquier cantidad de parámetros y variables que necesite, un cierre es realmente una combinación de:
- La función en sí, y El código (pero más importante, el cadena de alcance) donde se declara la función. Es decir, el entorno léxico de la función.
Cuando remember(5);
se ejecuta y se devuelve, la función devuelta aún puede acceder al valor de number
(es decir, 5
). Dado que la función se bloquea en la cadena de alcance, un cierre nos permite almacenar una instantánea del estado en el momento en que se crea el objeto de función. De hecho, una función será retener su cadena de alcance, incluso si se invoca en una ubicación otro que donde fue declarado. Nuevamente, ¡todo esto se debe al cierre!
Cierres y estado privado.
En resumen, hemos visto dos aplicaciones comunes y poderosas de cierres:
- Pasar argumentos implícitamente (es decir, a través de la cadena de ámbito)
- En la declaración de la función, almacenar una instantánea del alcance
Otra forma en que podemos aprovechar los cierres es crear variables «privadas» (es decir, privado estado). Al crear variables privadas, podemos limitar la capacidad de otro código en nuestra aplicación para poder mutar esos datos.
Considere el siguiente ejemplo:
function expandArray() {
let myArray = [];
return function () {
myArray.push(0);
return myArray;
};
}
let returnedFunction = expandArray();
En el ejemplo anterior, expandArray()
simplemente devuelve una función que agrega un nuevo elemento a myArray
y luego devuelve el valor actual de myArray
.
que hace expandArray()
tan poderosa es que tiene un fin privado mudable estado. Es decir, el valor de myArray
se puede actualizar según sea necesario, pero no se puede acceder a la variable en sí desde el exterior porque la función interna se cierra myArray
.
Como tal, la matriz se expande a medida que seguimos invocando la función devuelta:
console.log(returnedFunction()); // [0]
console.log(returnedFunction()); // [0, 0]
console.log(returnedFunction()); // [0, 0, 0]
Sabemos que los datos se conservan y también se puede modificar, pero no hay forma de que nada fuera del cierre en sí pueda acceder myArray
.
returnedFunction.myArray; // undefined
myArray; // Uncaught ReferenceError: count is not defined
Tener un estado privado puede beneficiar las aplicaciones que creamos, ya que los usuarios no podrían realizar operaciones no deseadas en esos datos por accidente. ¡Debido al cierre, no hay forma de que se pueda acceder a esos datos externamente!
Obtenga más información sobre el alcance y los cierres.
En JavaScript, el alcance y los cierres van de la mano. Cada vez que se define una función, se crea un cierre para esa función. Estrictamente hablando, entonces, cada función tiene cierre! Esto se debe a que las funciones se cierran sobre al menos otro contexto a lo largo de la cadena de alcance: el alcance global. Sin embargo, las capacidades de los cierres realmente brillan cuando se trabaja con funciones definidas dentro de otra función.
Para ver más de cerca el alcance y los cierres en JavaScript, consulte estos recursos:
O explore el programa Intermediate JavaScript Nanodegree para dominar el lenguaje de programación más popular del mundo.
COMIENZA A APRENDER