preloader

Ámbito de Variable y Concepto de «Closure» en JavaScript

Ámbito de Variable y Concepto de «Closure» en JavaScript

JavaScript es un lenguaje altamente orientado a funciones, brindándonos mucha flexibilidad. Una función puede crearse en cualquier momento, pasarse como argumento a otra función y luego ser llamada desde un lugar completamente diferente en el código.

Ya sabemos que una función puede acceder a variables que están fuera de su propio bloque.

Pero, ¿qué pasa si esas variables externas cambian después de que la función se crea? ¿La función verá los valores nuevos o los antiguos?

¿Y qué sucede si una función se pasa como parámetro y se llama desde otra parte del código? ¿Podrá acceder a las variables externas en el nuevo contexto?

Para entender estos escenarios y otros más complejos, profundizaremos en el ámbito de las variables y el concepto de closure.

Bloques de Código

En JavaScript, hay tres formas de declarar una variable: let, const (las modernas) y var (más antigua).

En este artículo utilizaremos let en los ejemplos, pero const se comporta de manera similar, así que este artículo también aplica para const. var tiene algunas diferencias notables que se tratarán en otro artículo.

Cuando una variable se declara dentro de un bloque de código {...}, solo es visible dentro de ese bloque.

Por ejemplo:

				
					{
  let message = "Hello"; // Solo visible dentro de este bloque
  alert(message); // Hello
}

alert(message); // Error: message no está definida

				
			

Esto nos permite aislar secciones de código que realizan tareas específicas, utilizando variables locales.

				
					{
  let message = "Hello";
  alert(message);
}

{
  let message = "Goodbye";
  alert(message);
}

				
			

Sin bloques separados, habría un error si se intenta declarar una variable con el mismo nombre:

				
					if (true) {
  let phrase = "Hello!";
  alert(phrase); // Hello!
}

alert(phrase); // Error: phrase no está definida

				
			

Esto es útil para crear variables locales específicas de una rama if o de un bucle for o while.

				
					for (let i = 0; i < 3; i++) {
  alert(i); // 0, luego 1, luego 2
}

alert(i); // Error: i no está definida

				
			

Funciones Anidadas

Una función es «anidada» cuando se crea dentro de otra función. Esto es posible en JavaScript y se utiliza para organizar el código.

				
					function sayHiBye(firstName, lastName) {
  function getFullName() {
    return firstName + " " + lastName;
  }

  alert("Hello, " + getFullName());
  alert("Bye, " + getFullName());
}

				
			

Aquí, la función anidada getFullName() se crea por conveniencia. Puede acceder a las variables externas y devolver el nombre completo.

Las funciones anidadas son bastante comunes en JavaScript y pueden devolverse como propiedades de un objeto o como el resultado en sí mismo. Luego, pueden usarse en otro lugar, manteniendo acceso a las mismas variables externas.

Por ejemplo, makeCounter crea una función «contador» que devuelve el siguiente número en cada invocación:

				
					function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();

alert(counter()); // 0
alert(counter()); // 1
alert(counter()); // 2

				
			

Alcance Léxico

El alcance léxico es crucial para entender cómo funcionan las variables y funciones en JavaScript. Cada función en ejecución, bloque de código {...} y el script completo tienen un objeto interno asociado conocido como «alcance léxico».

El objeto de alcance léxico consta de dos partes:

  1. Registro de entorno: un objeto que almacena todas las variables locales y otra información como el valor de this.
  2. Una referencia al entorno léxico externo asociado con el código externo.

En código simple sin funciones, solo hay un entorno léxico: el entorno global.

				
					let phrase = "Hello";

function say(name) {
  alert(`${name}, ${phrase}`);
}

say("John"); // "John, Hello"

				
			

Declaración de Funciones

Las funciones también son valores y se inicializan completamente al instante. Una declaración de función se convierte inmediatamente en una función lista para usar, a diferencia de let, que no se puede usar hasta que se declara.

				
					say("John"); // Funciona debido a la inicialización instantánea

function say(name) {
  alert(`Hello, ${name}`);
}

				
			

Entorno Léxico Interno y Externo

Cuando se ejecuta una función, se crea un nuevo entorno léxico para almacenar las variables locales y parámetros de esa llamada. Este entorno tiene una referencia al entorno léxico externo.

				
					function say(name) {
  let phrase = "Hello";

  alert(`${name}, ${phrase}`);
}

say("John"); // "John, Hello"

				
			

Devolviendo una Función

Al devolver una función desde otra función, se crea un nuevo entorno léxico que la función anidada recordará.

				
					function makeCounter() {
  let count = 0;

  return function() {
    return count++;
  };
}

let counter = makeCounter();
alert(counter()); // 0
alert(counter()); // 1

				
			

Clausura

Una clausura es una función que recuerda sus variables externas y puede acceder a ellas. Todas las funciones en JavaScript son clausuras naturales. Recuerdan automáticamente el entorno léxico donde se crearon.

				
					function f() {
  let value = 123;

  return function() {
    alert(value);
  }
}

let g = f();
g(); // 123

				
			

Recolección de Basura

Los entornos léxicos se eliminan de la memoria una vez que finaliza la llamada a la función, a menos que haya una función anidada que aún tenga acceso a ella.

				
					function f() {
  let value = 123;

  return function() {
    alert(value);
  }
}

let g = f();
g(); // 123

g = null; // El entorno léxico se limpia de la memoria

				
			

Optimizaciones

En la práctica, los motores de JavaScript intentan optimizar el uso de variables externas. Si una variable no se usa, puede ser eliminada.

				
					function f() {
  let value = Math.random();

  function g() {
    debugger; // En la consola, escribir alert(value) no mostrará la variable
  }

  return g;
}

let g = f();
g();

				
			

Con esto, tienes una visión general completa del alcance de las variables y el concepto de closure en JavaScript.

Related Post

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *