2

¿Qué es closure? Ejemplo de la clase explicado con JavaScript Visualizer.

Hola, si llegaste aqui es porque en la clase ¿Qué es closure? te quedaron muchas dudas sobre lo que pasa por debajo.
Espero que este aporte ayude a entender lo que pasa , vamos a ver que es lo que pasa con el ejercicio moneyBox() gráficamente con ayuda de JavaScript Visualizarer.

JavaScript Visualizer

Javascript Visualizer es una herramienta de visualización de contexto de ejecución, hoisting, closures y scopes en JavaScript.

<h3>Instrucciones</h3>

El vizualizador aún esta en fase Beta, lo que significa que por ahora solo soporta ES5, asi que tendermos que hacer ciertos cambios es el código de la clase.

const moneyBox = () => {
    let saveCoins = 0
    const countCoins = (coins) => {
        saveCoins += coins
        console.log(`MoneyBox: $${saveCoins}`)
    }
    return countCoins
}

let myMoneyBox = moneyBox()
myMoneyBox(4)// 4myMoneyBox(6)// 10myMoneyBox(10)// 20

Con estos cambios el visualizador ejecutara nuestro código sin problemas.

var moneyBox = function() {
    var saveCoins = 0;
    var countCoins = function(coins) {
        saveCoins += coins;
        console.log(saveCoins);
    };
    return countCoins;
};

var myMoneyBox = moneyBox();
myMoneyBox(4);	//4
myMoneyBox(6);	//10
myMoneyBox(10);	//20
<h1>Ejecución</h1>

En la primera ejecución y en cada llamada a una nueva función se crea un contexto de ejecución la cual tiene dos fases:

  • Creación -> En el contexto objeto global se crean el el objeto global, el objeto this y los espacios me memoria para las funciones y variables con un valor por defecto de undefined.
  • Ejecución -> Se ejecuta linea por linea definiendo los valores reales de tus variables y funciones.
<h3>Fase de creación</h3>
fewo.png
<h3>Fase de ejecución</h3>
ui.dev_ (2).png

Como se puede obserbar el valor de moneyBox paso de undefined a fn() ya que su contenido es una función.

<h1>Linea 10</h1>

El siguiente línea tiene algo más de complejidad.

var myMoneyBox = moneyBox();
//moneyBox() se ejecuta //y lo que retorna se guarda en myMoneyBox

Cuando llegamos a esta línea debemos ejecutar primero moneyBox() el cual ya tiene definido una función fn() que apunta a la línea 1.

Cada vez que se invoca una función se crea un nuevo contexto de ejecución, tambien crea un objeto this pero a diferencia del contexto global, crea un objeto llamado arguments.

ui.dev_ (3).png
  • Tambien tiene las dos fases de creación y ejecución

  • El objeto arguments simplemente recibe los argumentos pasados cuando invocamos la funcion, es este caso queda vacío.

  • Las variables saveCoins y countCoins se declaran con el valor por defecto de undefined.

Este es el bloque de código que se ejecutará.

var moneyBox = function() {
    var saveCoins = 0;
    var countCoins = function(coins) {
        saveCoins += coins;
        console.log(saveCoins);
    };
    return countCoins;
};
ui.dev_ (5).png
  • Las variable saveCoins obtiene su valor 0 y countCoins hará referencia a una función fn().

  • La función retornara countCoins: fn().

<h4>El Closure</h4>
ui.dev_ (6).png
  • Cuando moneyBox() termine de ejecutarse, JavaScript Visualizer creara un closure scope.

  • Dentro de Closure Scope existe el mismo entorno de ejecución que en moneyBox es este caso => anonymous Execution Context.

Esto pasa debido a que tenemos una función anidada dentro de otra.

ui.dev_ (8).png
  • myMoneyBox que esta en el contexto global recibe una función fn() que hace referencia al Closure Scope.
<h3>Ejecución de las ultimas lineas</h3>

Dado que myMoneyBox ahora es una función hace refencia a función que se almacena en countCoins que recibe un parametro coins

var moneyBox = function() {
    var saveCoins = 0;
	//==============================var countCoins = function(coins) {
        saveCoins += coins;
        console.log(saveCoins);
    };
	//==============================return countCoins;
};
<h4>Últimas lineas de código</h4>
myMoneyBox(4);	//4
myMoneyBox(6);	//10
myMoneyBox(10);	//20

Esto es lo que sucede cuando ejecutamos myMoneyBox(4).

ui.dev_ (10).png
  • Un nuevo contexto de ejecución se crea dentro de Closure scope en la fase de creación.
  • arguments recibe un parámetro que esta vez es 4.
  • Dado el el nombre del parametro es coins esta se define como variable local dentro de esta función.
ui.dev_ (11).png
  • Durante la fase de efecución la línea saveCoins += coins suma 0 + 4 y lo almacena en saveCoins del closure scope.
  • Luego muestra en consola el número 4 que al no existir en la anonymous Execution Context la busca en el scope padre más cercano que es Closure Scope

El Closure Scope queda así con el valor de saveCoins modificado

ui.dev_ (12).png

Notaran que con cada llamada a la función guardara el dato es su contexto de ejecución.

Cuando ejecutamos myMoneyBox(6) primero en fase de creación y luego en ejecución.
Creación
ui.dev_ (13).png
Ejecucuión
ui.dev_ (14).png

Cuando ejecutamos myMoneyBox(10) primero en fase de creación y luego en ejecución.
Creación
ui.dev_ (15).png
Ejecucuión
ui.dev_ (16).png

Conclusión

Si algunas cosas no te quedaron claras les recomiento el siguiente artículo.

Tambien pudes probar el código tu mismo en el siguiente enlace.

Escribe tu comentario
+ 2