Saltar al contenido

Cierres

Comprender los cierres en JavaScript

En JavaScript, los cierres son un concepto fundamental y poderoso que permite crear funciones con datos preservados de su entorno léxico. Esta guía proporcionará una exploración en profundidad de los cierres, acompañada de explicaciones detalladas y ejemplos de código prácticos para consolidar tu comprensión.

¿Qué es un cierre?

Un cierre es la combinación de una función y el entorno léxico dentro del cual fue declarada dicha función. Este entorno consiste en cualquier variable local que estuviera en el ámbito en el momento en que se creó el cierre.

Ejemplo de un cierre

Considera el siguiente ejemplo:


Output appears here after Run.

En este ejemplo, greetByName es un cierre. Captura las variables greeting y name del ámbito de la función greet.

Cuando se llama a la función greet con el argumento 'John', crea una variable local greeting y una función greetByName. Luego, la función greet devuelve la función greetByName. Incluso después de que la función greet haya terminado de ejecutarse, la función greetByName devuelta sigue teniendo acceso a las variables greeting y name. Esto se debe a que greetByName es un cierre, lo que significa que recuerda el entorno en el que fue creado.

¿Por qué usar cierres?

Los cierres permiten la encapsulación de datos y la creación de variables privadas. Permiten que las funciones conserven el acceso a variables de su ámbito contenedor (o envolvente) incluso después de que dicho ámbito haya terminado de ejecutarse.

Creación de un cierre básico

Considera el siguiente ejemplo:


Output appears here after Run.

Cuando se invoca outerFunction, crea outerVariable e innerFunction. Luego devuelve innerFunction. La innerFunction devuelta conserva el acceso a outerVariable incluso después de que outerFunction haya terminado de ejecutarse.

Casos de uso prácticos de los cierres

Privacidad de datos

Los cierres se pueden usar para crear datos privados que no pueden ser accedidos desde el ámbito global.


Output appears here after Run.

En este ejemplo, count es una variable privada que solo puede ser accedida y modificada por la función anónima devuelta. Cada vez que se llama a la función, incrementa y devuelve el count actualizado.

Fábricas de funciones

Los cierres se pueden usar para crear fábricas de funciones que generan funciones especializadas.


Output appears here after Run.

Aquí, createMultiplier genera funciones que multiplican un número dado por un multiplier especificado. Cada función devuelta conserva el acceso al valor de multiplier a través del cierre.

Cierres en bucles

Los cierres pueden ser complicados cuando se usan dentro de bucles. Considera el siguiente ejemplo:


Output appears here after Run.

En este código, el bucle se completa y luego se ejecutan las tres funciones de devolución de llamada setTimeout, registrando el valor de i, que es 4 después de que termina el bucle. Esto sucede porque var tiene un ámbito de función.

Para solucionarlo, usa let, que tiene un ámbito de bloque:


Output appears here after Run.

INFO

Siempre usa let o const en lugar de var para evitar problemas de ámbito y asegurar que las variables tengan el ámbito adecuado.

Cierres y gestión de memoria

Los cierres pueden causar fugas de memoria si no se usan correctamente. Dado que los cierres retienen referencias a su ámbito exterior, las variables no utilizadas pueden persistir en la memoria más tiempo del necesario.

WARNING

Ten cuidado con el uso de memoria al crear cierres. Asegúrate de que los cierres no capturen innecesariamente objetos grandes o elementos del DOM para evitar fugas de memoria.

Patrones avanzados de cierres

Patrón de módulo

El patrón de módulo aprovecha los cierres para crear miembros privados y públicos dentro de una función.


Output appears here after Run.

En este ejemplo, CounterModule es una expresión de función invocada inmediatamente (IIFE, por sus siglas en inglés) que devuelve un objeto con métodos públicos (increment y reset). La variable count permanece privada y no puede ser accedida directamente.

Cierres en frameworks modernos de JavaScript

Los cierres son particularmente importantes en frameworks modernos de JavaScript como React. En React, los cierres ayudan a gestionar el estado y los efectos secundarios dentro de los componentes funcionales.


javascript
import React, { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);

    function increment() {
        setCount(prevCount => prevCount + 1);
    }

    return (
        <div>
            <p>{count}</p>
            <button onClick={increment}>Increment</button>
        </div>
    );
}

En este ejemplo, useState se usa para crear una variable de estado count y una función setCount para actualizarla. La función increment forma un cierre, capturando setCount y count del ámbito del componente. Nota: En React, los cierres a veces pueden capturar un estado obsoleto si las dependencias no se gestionan correctamente en hooks como useEffect.

INFO

Practica la creación y el uso de cierres en diferentes contextos para comprender completamente su potencial y limitaciones. Son una herramienta esencial en el conjunto de herramientas de cualquier desarrollador de JavaScript.

Mejores prácticas para usar cierres

  1. Limitar el ámbito: Evita crear cierres dentro de bucles o estructuras profundamente anidadas a menos que sea necesario para prevenir fugas de memoria y problemas de rendimiento.
  2. Minimizar variables capturadas: Captura solo las variables que necesitas dentro del cierre para reducir el consumo de memoria.
  3. Evitar capturas grandes: No captures objetos grandes o DOM elementos dentro de los cierres para evitar la retención innecesaria de memoria.
  4. Usar let y const: Prefiere siempre let o const sobre var para garantizar un ámbito correcto y evitar comportamientos no deseados.
  5. Limpieza: Siempre que sea posible, limpia las referencias capturadas por los cierres para evitar fugas de memoria, especialmente en aplicaciones de ejecución prolongada.

Conclusión

Los cierres son una característica poderosa en JavaScript, que habilita la privacidad de datos, fábricas de funciones y patrones avanzados como los módulos. Comprender y utilizar los cierres de manera efectiva puede conducir a un código más robusto y mantenible. Al dominar los cierres, mejorarás tu capacidad para escribir código JavaScript eficiente, seguro y limpio.

Práctica

¿Qué son los cierres en JavaScript?

¿Te resulta útil?

Vista previa dual-run — compárala con las rutas Symfony en producción.