Closures en JavaScript
Este artículo explica los closures en JavaScript.
YouTube Video
Closures en JavaScript
En JavaScript, un 'closure' es uno de los conceptos muy importantes y poderosos. Al comprender los closures, puedes adquirir conocimientos útiles en muchas situaciones, como el comportamiento y el alcance de las funciones, así como el manejo asincrónico y de eventos en JavaScript. Aquí, explicaremos en detalle todo, desde la definición básica de los closures hasta ejemplos concretos y sus aplicaciones.
¿Qué es un Closure?
Un closure se refiere al mecanismo mediante el cual una función puede acceder a las variables en su alcance de creación, incluso cuando se llama fuera de ese alcance. Al utilizar los closures, las funciones se hacen capaces de 'recordar' continuamente las variables externas.
Los closures consisten en los dos elementos siguientes.
-
Definición de la función (la función en sí misma)
-
Ámbito en el que se define la función (variables y otras funciones fuera de la propia función)
En JavaScript, los closures son posibles porque las funciones tienen la capacidad de acceder a las variables dentro del alcance en el que fueron creadas.
Ejemplo Básico
Primero, veamos un ejemplo básico de un closure. En el siguiente código, outerFunction
devuelve una función llamada innerFunction
. El punto importante es que innerFunction
puede acceder a la variable count
definida dentro del alcance de outerFunction
.
1function outerFunction() {
2 let count = 0;
3
4 function innerFunction() {
5 count++;
6 console.log(`Current count: ${count}`);
7 }
8
9 return innerFunction;
10}
11
12const counter = outerFunction();
13counter(); // Current count: 1
14counter(); // Current count: 2
15counter(); // Current count: 3
Cómo Funcionan las Closures
Como se observa en el ejemplo anterior, count
se conserva en innerFunction
incluso después de que outerFunction
se haya ejecutado. innerFunction
puede seguir accediendo al alcance de outerFunction
, y por lo tanto, count
se actualiza dentro de innerFunction
. Este es el mecanismo básico de un closure.
innerFunction
es la función que se asigna a la variable counter
, y podemos observar que el estado de count
se conserva, incluso después de que outerFunction
haya finalizado su ejecución. Esto se debe a que JavaScript 'recuerda' continuamente el alcance en el momento de la definición de la función.
Aplicación: Closures como Variables Privadas
Los closures pueden ser utilizados como 'variables privadas' en la programación orientada a objetos. Normalmente, en JavaScript, las propiedades de los objetos son accesibles directamente desde el exterior, pero al usar closures, es posible evitar la manipulación directa de las variables dentro del alcance de la función desde el exterior.
En el siguiente ejemplo, la función createCounter
utiliza un closure para crear un contador y devuelve un contador con una variable privada count
.
1function createCounter() {
2 let count = 0;
3
4 return {
5 increment: function() {
6 count++;
7 console.log(`Count: ${count}`);
8 },
9 decrement: function() {
10 count--;
11 console.log(`Count: ${count}`);
12 },
13 getCount: function() {
14 return count;
15 }
16 };
17}
18
19const myCounter = createCounter();
20myCounter.increment(); // Count: 1
21myCounter.increment(); // Count: 2
22myCounter.decrement(); // Count: 1
23console.log(myCounter.getCount()); // 1
En este ejemplo, count
está dentro del alcance de la función createCounter
, por lo que no puede ser accesada directamente desde el exterior. Sin embargo, puede manipularse a través de los métodos increment
y decrement
. De esta manera, usando closures, puedes incorporar el concepto de variables privadas en JavaScript.
Ejemplos prácticos de closures
Combinación con funciones de retrollamada
Los closures se utilizan a menudo en combinación con funciones de callback para manejar el procesamiento asíncrono. Por ejemplo, consideremos un ejemplo que utiliza un temporizador.
1function startTimer(duration) {
2 let timeLeft = duration;
3
4 function countdown() {
5 console.log(`Time left: ${timeLeft} seconds`);
6 timeLeft--;
7
8 if (timeLeft >= 0) {
9 setTimeout(countdown, 1000);
10 }
11 }
12
13 countdown();
14}
15
16startTimer(5);
17// Time left: 5 seconds
18// Time left: 4 seconds
19// Time left: 3 seconds
20// Time left: 2 seconds
21// Time left: 1 second
22// Time left: 0 seconds
En este ejemplo, la función countdown
accede a la variable timeLeft
dentro del ámbito de startTimer
. De esta manera, los closures son muy útiles para el procesamiento asíncrono como temporizadores, ya que mantienen el estado de las variables a lo largo del tiempo.
Manejadores de eventos
Los closures también son convenientes al configurar manejadores de eventos. En el siguiente ejemplo, se utiliza un closure para registrar el número de veces que se pulsa un botón.
1function setupClickCounter(buttonId) {
2 let clickCount = 0;
3
4 const button = document.getElementById(buttonId);
5 button.addEventListener('click', function() {
6 clickCount++;
7 console.log(`Button clicked ${clickCount} times`);
8 });
9}
10
11setupClickCounter('myButton');
En este caso, clickCount
aumenta con cada clic y su valor se conserva. Al usar closures, puedes asignar un contador independiente a cada botón.
Conclusión
Los closures son un concepto que simboliza la flexibilidad y el poder de JavaScript. Contienen variables encerradas dentro del ámbito de una función y permiten operar con esas variables a través de funciones accesibles externamente. Al comprender y utilizar este mecanismo, puedes adquirir técnicas más avanzadas en la programación con JavaScript.
Los closures se aplican en diversas situaciones, desde el manejo de eventos y el procesamiento asíncrono hasta incluso pseudoimplementaciones de programación orientada a objetos.
Puedes seguir el artículo anterior utilizando Visual Studio Code en nuestro canal de YouTube. Por favor, también revisa nuestro canal de YouTube.