Compartir en Twitter
Go to Homepage

DOMINANDO LOS CLOSURES EN JAVASCRIPT: GUÍA COMPLETA 2026

January 8, 2026

Introducción a los Closures en JavaScript

Los closures representan uno de los conceptos más poderosos y fundamentales en JavaScript. Una función interna tiene acceso a las variables de su función externa, incluso después de que esta última haya terminado su ejecución. Esta característica permite crear comportamientos avanzados en el código, como el mantenimiento de estado privado o la implementación de patrones modulares.

En el contexto actual de JavaScript en 2026, los closures siguen siendo esenciales, aunque características introducidas en versiones recientes de ECMAScript, como el alcance de bloque con let y const, han simplificado algunos casos de uso tradicionales. Sin embargo, comprender los closures a fondo es clave para dominar el lenguaje y escribir código eficiente y mantenible.

Ejemplos Básicos de Closures

Consideremos un primer ejemplo para ilustrar el concepto.

function generadorNumero() {
    var num = 1;
    function verificarNumero() {
        console.log(num);
    }
    num++;
    return verificarNumero;
}

var funcion = generadorNumero();
funcion(); // Salida: 2

Aquí, la función interna verificarNumero accede a la variable num declarada en la función externa generadorNumero. Aunque generadorNumero ha completado su ejecución, la función retornada mantiene el acceso a num gracias al closure.

Otro ejemplo demuestra que el orden de declaración no afecta el acceso.

function saludar() {
    var decir = function () {
        console.log(saludo);
    };
    var saludo = "¡Hola, mundo!";
    return decir;
}

var closureSaludo = saludar();
closureSaludo(); // Salida: ¡Hola, mundo!

La variable saludo se define después de la función interna, pero esta aún puede utilizarla porque el entorno léxico se establece en el momento de creación de la función.

Contexto de Ejecución y su Rol en los Closures

Para entender los closures en profundidad, es necesario explorar el contexto de ejecución. JavaScript gestiona la evaluación del código mediante contextos de ejecución, que se apilan en una estructura LIFO conocida como pila de ejecución.

Solo un contexto de ejecución está activo en cualquier momento, lo que refleja el naturaleza de hilo único de JavaScript. Cuando una función se invoca, se crea un nuevo contexto de ejecución y se coloca en la cima de la pila.

Cada contexto de ejecución incluye un entorno léxico, que gestiona los identificadores y sus asociaciones. Este entorno consiste en un registro de entorno con los enlaces locales y una referencia al entorno externo.

// Representación abstracta de un entorno léxico
LexicalEnvironment = {
  EnvironmentRecord: {
    // Enlaces de identificadores
  },
  outer: <referencia al entorno externo>
};

Los entornos léxicos se anidan, formando una estructura jerárquica donde el entorno global es la capa más externa.

Entorno Léxico y Cadena de Alcance

El entorno léxico define la asociación de identificadores basada en la estructura anidada del código. Cada vez que se evalúa una función, se crea un nuevo entorno léxico con referencia a su entorno padre.

La cadena de alcance surge de esta anidación: una función tiene acceso a su propio alcance, al de su función padre, y así sucesivamente hasta el alcance global.

Veamos un ejemplo con funciones anidadas.

var x = 10;

function foo() {
    var y = 20;
    function bar() {
        var z = 15;
        return x + y + z;
    }
    return bar;
}

var prueba = foo();
console.log(prueba()); // Salida: 45

La función bar accede a x (global), y (de foo) y z (local). Esta cadena de alcance se establece estáticamente en el momento de creación de la función, no en el de su invocación.

El motor de JavaScript realiza una búsqueda en esta cadena cuando resuelve identificadores, comenzando por el entorno local y ascendiendo hasta el global.

Cómo Funcionan los Closures Internamente

Un closure se forma cuando una función interna referencia variables del entorno externo. La función “recuerda” su entorno léxico porque mantiene una referencia permanente a él.

En el ejemplo anterior, cuando foo retorna bar, el entorno de foo no se destruye inmediatamente porque bar lo referencia. El recolector de basura de JavaScript mantiene vivas las variables necesarias mientras exista una referencia a través del closure.

Esto permite patrones como fábricas de funciones o mantenimiento de estado privado.

function crearContador(inicio) {
    var conteo = inicio;
    return function () {
        return ++conteo;
    };
}

var contador1 = crearContador(0);
var contador2 = crearContador(10);

console.log(contador1()); // 1
console.log(contador1()); // 2
console.log(contador2()); // 11

Cada instancia de contador mantiene su propio estado gracias a closures independientes.

Problemas Comunes con Closures en Bucles

Un error frecuente ocurre al usar closures en bucles con variables declaradas con var, que tiene alcance de función.

var resultado = [];
for (var i = 0; i < 5; i++) {
    resultado[i] = function () {
        console.log(i);
    };
}

resultado[0](); // 5
resultado[1](); // 5
// Todas imprimen 5

Todas las funciones comparten el mismo entorno, donde i termina valiendo 5 después del bucle.

Una solución clásica es crear un entorno adicional mediante una función inmediata.

var resultado = [];
for (var i = 0; i < 5; i++) {
    resultado[i] = (function (x) {
        return function () {
            console.log(x);
        };
    })(i);
}

resultado[0](); // 0
resultado[1](); // 1
// Funciona correctamente

En JavaScript moderno (desde ES2015), usar let resuelve esto automáticamente gracias al alcance de bloque.

var resultado = [];
for (let i = 0; i < 5; i++) {
    resultado[i] = function () {
        console.log(i);
    };
}

resultado[0](); // 0
resultado[1](); // 1

Cada iteración crea un nuevo binding para i, eliminando la necesidad de closures adicionales en este caso.

Aplicaciones Prácticas de Closures

Los closures habilitan patrones avanzados como el módulo, que simula variables privadas.

function crearModulo() {
    var privado = "Secreto";
    return {
        obtener: function () {
            return privado;
        },
        establecer: function (valor) {
            privado = valor;
        },
    };
}

var modulo = crearModulo();
console.log(modulo.obtener()); // Secreto
modulo.establecer("Nuevo");
console.log(modulo.obtener()); // Nuevo
console.log(modulo.privado); // undefined

La variable privado permanece inaccesible desde fuera, promoviendo encapsulamiento.

Otro uso común es en currying, donde closures retienen argumentos parciales.

function sumar(a) {
    return function (b) {
        return a + b;
    };
}

var sumar5 = sumar(5);
console.log(sumar5(3)); // 8
console.log(sumar5(10)); // 15

Esto facilita la creación de funciones especializadas.

En programación asíncrona, closures capturan valores en callbacks.

function retrasarMensaje(mensaje, tiempo) {
    setTimeout(function () {
        console.log(mensaje);
    }, tiempo);
}

retrasarMensaje("Hola después de 1s", 1000);

El callback retiene acceso a mensaje incluso después de que retrasarMensaje retorne.

Closures en el JavaScript Moderno

Aunque los closures permanecen inalterados en su mecánica fundamental, características como let, const y arrow functions han influido en su uso. Las arrow functions heredan el this léxico, complementando closures en manejadores de eventos.

Además, patrones como Promises y async/await han reducido la dependencia de closures en algunos escenarios asíncronos, pero estos aún operan internamente con closures.

En 2026, con ECMAScript consolidado en versiones recientes, los closures siguen siendo la base para bibliotecas y frameworks modernos, permitiendo abstracciones potentes.

Ventajas y Consideraciones de Rendimiento

Los closures ofrecen encapsulamiento de datos, reducción de variables globales y código más modular. Sin embargo, mantienen referencias a entornos, lo que puede impedir la recolección de basura si no se manejan con cuidado, potencialmente causando fugas de memoria en aplicaciones grandes.

Es recomendable liberar referencias explícitamente cuando ya no sean necesarias, especialmente en listeners de eventos.

Conclusiones

Los closures constituyen un pilar esencial de JavaScript, permitiendo acceso persistente a variables externas y habilitando patrones de diseño avanzados. Su comprensión profunda facilita la escritura de código robusto y eficiente.

Desde ejemplos básicos hasta aplicaciones complejas, los closures demuestran la flexibilidad del lenguaje. En el panorama actual de 2026, combinados con características modernas, siguen siendo indispensables para desarrolladores profesionales.

Dominar los closures no solo resuelve problemas inmediatos, sino que eleva la calidad general del código, promoviendo mejores prácticas en programación funcional y modular.