Comprender cómo una función puede recordar variables de su entorno exterior, incluso después de haberse ejecutado, es fundamental para escribir código flexible y potente en JavaScript. Esto es exactamente lo que logran los closures, y dominar este concepto marca una diferencia importante en la forma de estructurar aplicaciones.
¿Qué es un closure y cómo se relaciona con el ámbito léxico?
Un closure es una función que tiene acceso a variables de un ámbito externo, incluso después de que esa función externa ya haya terminado de ejecutarse [0:08]. Para comprender esta idea es necesario conocer el ámbito léxico (lexical scope): cuando una función se declara, se crea un ámbito léxico que le permite acceder tanto a sus propias variables como a las de ámbitos superiores [0:22].
En la práctica esto significa que si dentro de una función externa (outer function) se define una función interna (inner function), esta última puede leer y utilizar las variables de la primera.
¿Cómo se ve un closure en código?
El ejemplo más directo consiste en crear una función outerFunction con una variable outerVariable que contiene el texto "I am from Outer function" [0:42]. Dentro de ella se define innerFunction, que ejecuta un console.log de esa variable externa y luego se retorna [1:06].
javascript
function outerFunction() {
const outerVariable = "I am from Outer function";
function innerFunction() {
console.log(outerVariable);
}
Al ejecutar el programa, la consola muestra I am from Outer function [1:50]. Esto confirma que innerFunctionaccedió a la variable de su función contenedora, y eso es precisamente un closure.
¿Por qué hay que tener cuidado con el uso de memoria?
Los closures conservan referencias a las variables externas, lo que implica consumo de memoria. Para ilustrarlo se crea una función createCounter con una variable count inicializada en cero [2:16]. Internamente retorna una función que incrementa count con count++ y lo imprime con console.log [2:32].
javascript
function createCounter() {
let count = 0;
return function () {
count++;
console.log(count);
};
}
Cada llamada a createCounter genera un ámbito léxico independiente [3:15]. Por eso counterA llega a 2 mientras counterB arranca en 1: cada instancia almacena su propio valor de count en memoria. Esto demuestra que, aunque los closures son muy útiles, conviene no abusar de ellos para evitar un consumo excesivo de recursos [3:30].
¿Cómo manejar diferentes contextos con closures?
Otro uso práctico es generar funciones con contextos distintos a partir de una misma estructura. Se crea una función other con una variable message que contiene "Hello, " [3:50]. Dentro se define inner, que recibe un parámetro name y lo concatena con el mensaje externo [4:18].
javascript
function other() {
const message = "Hello, ";
function inner(name) {
console.log(message + name);
}
closureA("Alice"); // Hello, Alice
closureB("Bob"); // Hello, Bob
Al ejecutar se obtiene Hello, Alice y Hello, Bob [5:06]. Cada closure mantiene su propio contexto pero comparte la misma lógica interna, lo que permite crear funciones flexibles y reutilizables.
¿Qué ventajas ofrecen los closures en la práctica?
Permiten trabajar con diferentes ámbitos dentro de una misma estructura de funciones.
Facilitan la creación de funciones que recuerdan estado entre ejecuciones, como contadores o acumuladores.
Hacen posible generar múltiples contextos a partir de una sola función base, personalizando el comportamiento con parámetros.
Su uso debe ser consciente y medido, ya que cada closure retiene referencias en memoria que no se liberan automáticamente [5:30].
Si ya has experimentado con closures en tus proyectos o tienes dudas sobre cómo aplicarlos de forma eficiente, comparte tu experiencia en los comentarios.
Un closure es cuando una función "recuerda" el entorno o contexto en el que fue creada, incluso después de que la función haya terminado de ejecutarse. Es como si guardara una pequeña "memoria" de las variables que estaban en su alcance cuando se creó.
¿Cómo se utiliza?
Se usa mucho en JavaScript cuando queremos que una función interna tenga acceso a las variables de una función externa, incluso después de que la función externa haya finalizado. Nos ayuda a mantener el estado de ciertas variables sin exponerlas a todo el programa, lo que mejora la seguridad del código.
¿Por qué es importante?
Control del estado: Permite que las funciones retengan datos.
Privacidad: Las variables dentro del closure no son accesibles desde afuera, ayudando a encapsular la lógica.
Evita colisiones: Puedes evitar que otras partes de tu programa cambien los valores de esas variables.
Ejemplo sencillo:
Imagina que tu mamá te da una caja para guardar tu mesada. Cada vez que recibes dinero, lo metes ahí. Con el tiempo, esa caja sigue recordando cuánto has ahorrado. Tú puedes abrirla y agregar más, pero nadie más puede ver cuánto tienes o tocar tu dinero. Así funcionan los closures: mantienen el dinero (o en nuestro caso, las variables) a salvo y accesibles solo para ti.
functioncrearCajaDeAhorros(){let dinero =0;// Esta es la "memoria" o estado de la cajareturnfunction(agregarDinero){ dinero += agregarDinero;console.log(`Tienes ahora $${dinero} en tu caja de ahorros.`);};}const miCaja =crearCajaDeAhorros();// Creamos una nueva cajamiCaja(50);// Añadimos $50miCaja(30);// Añadimos $30 más
Bravo, muy buena información y ejemplo, me has ayudado a comprender closure mucho más. Te deseo mucho exitos bro, felicidades.
De verdad que tu comentario me ayudo mucho a entender esta clase, mil gracias.
En programación, un closure, también conocido como clausura o cierre, es una función que recuerda y tiene acceso al entorno en el que se creó, incluso después de que la función externa que la creó haya terminado de ejecutarse.
En otras palabras, un closure es una función que encapsula un dato (que puede ser una variable o un objeto) y recuerda el estado del entorno en el que se definió. Esto permite que la función interna acceda y utilice variables o valores de la función externa, incluso después de que esta haya finalizado.
Hemos bajado los índices de ignorancia un poquitico, hemos cumplido!
Le di muchas vueltas a este tema, y con ayuda de un video en YT y ChatGPT generé este pequeño resumen. Espero les sirva y si pueden aportar sería excelente. 👁️ ojo les recomiendo ver el video que dejo al final:
Introducción 🔗
Si estás aprendiendo JavaScript, es posible que hayas oído hablar de los closures (o cierres). Aunque suena complicado, en realidad es una herramienta muy útil que nos permite recordar valores incluso después de que una función haya terminado de ejecutarse.
¿Qué es un Closure?
Un closure ocurre cuando una función dentro de otra función recuerda las variables de la función externa, incluso después de que esta última haya finalizado.
Un closure tiene estas características:
Es una función dentro de otra función.
Utiliza variables de la función que la contiene.
Puede ejecutarse desde otro lugar y seguir recordando esas variables.
Ejemplo Básico
Imagina que tenemos una función que almacena un mensaje y otra función dentro de ella que lo muestra:
functioncrearSaludo(){let mensaje ="¡Hola!";functionmostrarSaludo(){console.log(mensaje);}return mostrarSaludo;}const saludo =crearSaludo();saludo();// Salida: "¡Hola!"```Aquí, la función `mostrarSaludo` sigue recordando la variable `mensaje`, aunque `crearSaludo` ya terminó su ejecución.
### ¿Para qué se usan los Closures?
Los closures son muy útiles en diferentes situaciones:
1. **Proteger variables**
* Evitan que otros puedan modificar datos importantes sin permiso.
2. **Crear funciones personalizadas**
* Podemos hacer funciones que generen otras funciones con configuraciones específicas.
3. **Trabajar con eventos y asincronía**
* Ayudan a recordar valores en temporizadores (`setTimeout`, `setInterval`) y eventos.
4. **Mejorar el rendimiento**
* Permiten almacenar resultados de funciones para no recalcular lo mismo varias veces.
### Ejemplo Práctico
Un contador que recuerda su número sin usar variables globales:
```js
functioncontador(){let cuenta =0;returnfunction(){ cuenta++;console.log(cuenta);};}const miContador =contador();miContador();// Salida: 1miContador();// Salida: 2miContador();// Salida: 3```Aquí, cada vez que ejecutamos `miContador()`, la función sigue recordando el valor de `cuenta`.### ConclusiónLos closures en JavaScript son una forma poderosa de trabajar con funciones y datos.Te permiten recordar valores, crear código más seguro y reutilizable, y son clave para entender el lenguaje de manera más profunda.📽️LINK:21.CLAUSURAS(Closures)ENJAVASCRIPT
muchas gracias! la verdad que no habia entendido nada con este video, se agradece muchisimo el aporte
Muchas gracias hermano, esta vez entendí más con este comentario
Para entender mejor
Sara!
Haz compartido ORO sin ningun tipo de interes!
Gracias miles! Tremendo aporte!
Yo al principio no entendi nada, pero ya al final de la clase segui sin entender nada :'v
X2
Pero nunca se ejecuta el closureB ? En ambos casos ejecuta el closureA. De igual manera imagino que el resultado devuelto es el mismo.
functioncreateCounter(){let count=0returnfunction(){ count++console.log(count)}}const counterA =createCounter()counterA()counterA()const counterB=createCounter()counterB()```quiero suponer que es porque nosotros estamos generando lo datos(nombres) a nuestro antojo, pero como puedes ver en el codigo de "counterA" le decimos que sume de a uno por eso en la consola sale 12 y al no tener mas "counterA" pasa al "counterB" volviendo al 1, lo cual en la consola sale 121
tal cual, no me gusta que no haya un quality check o correcciones antes de publicar el video, uno ve que solo improvisan sobre la marcha
¿Cómo la función "interna" sabe que debe tomar como parámetros los datos suministrados a "closureA" y "closureB"?.
Cuando asignamos la función externa a las variables closureA y closureB, estamos creando una nuevo contexto de la función interna que se encuentra dentro de externa. Cuando ejecutamos closureA("Parámetro") o closureB("Parámetro"), estamos llamando a la función interna que se encuentra dentro del contexto de externa. La función interna tiene acceso a las variables de su ámbito superior, incluyendo la variable message y los parámetros que se le pasan.
Para ser más claro, cuando llamamos a closureA() o closureB() estamos llamando a la función interna que se encuentra dentro de la función externa, y estamos pasando los parámetro a esa función interna.
Como explica Juan Diego Caro García, solo agrego: que las variables closureA y closureB es como si se guardara la función interna por eso reciben el argumento sin problemas. Y tener en cuenta que la función externa retorna la función interna. Espero que ayude la explicación.
Un closure es como una función con un dato privado que solo puede ser modificado por funciones internas. Si haces lo mismo sin función, estás dejando ese dato expuesto al resto del programa.
No entendi nada del segundo ejemplo...
El primerito estuvo MELO-Caramelo!
Pero el segundo, me genera un Buffering en el craneo...
Y por el contrario, el tercero, peor, no tengo ni la mas minima idea de como seria
Tranquilo tocayo, me paso igual, pero con paciencia y leyendolo bien, escuchando la explicación de la profe varias veces lo entendí
En el segundo la función createCounter devuelve una función anonima, esa función anonima al momento de crearse counterA en la línea const counterA = createCounter()"le tira una foto al ambito" y guarda las variables como estaban en ese momento. luego cuando la ejecutas counterA() es como si tuvieras a la función anonima más la variable count que guardó del ámbito
Un closure es cuando una función recuerda variables del lugar donde fue creada.
Si hago const countA = createCounter(), se crea un entorno propio con su count.
Al llamar countA(), solo corre la función interna usando el mismocount (no se reinicia).
Puedo crear varios entornos independientes:
const countA = createCounter(); const countB = createCounter(); …
Cada uno lleva su propiocount.
Analogía: es como abrir varias pestañas del IDE (countA, countB…), cada pestaña guarda sus variables y las va actualizando cuando la ejecutas.
Esta si no entendí nada
Closure y contexto local no son lo mismo, aunque están relacionados. Un closure es una función que recuerda el entorno en el que fue creada, lo que incluye variables de un contexto local, incluso después de que el contexto haya terminado su ejecución. El contexto local se refiere simplemente al alcance de las variables dentro de una función específica. En resumen, un closure permite acceder a variables de un contexto local después de que la función ha finalizado, lo que no ocurre con el contexto local por sí solo.
Desde que estoy en Platzi nunca me había confundido tanto en una clase, no entendí nada, creo que no fue la mejor clase de la profe lo bueno es que me toco investigar por mis medios.
Es que fue muy rápido, no se detuvo a explicar o de repente asumió que todos ya somos expertos.
NOTAS (o resumen wtv):
Closures (Clausuras) — Explicación completa
El concepto central
Un closure es cuando una función "recuerda" las variables del lugar donde fue creada, incluso después de que ese lugar ya terminó de ejecutarse y, en teoría, debería haber desaparecido.
Es la consecuencia directa de todo lo que ya vimos con lexical scope: una función siempre tiene acceso a las variables del scope donde fue escrita. Un closure es simplemente ese acceso, pero "congelado" y llevado hacia afuera, sobreviviendo más allá de la vida normal de esas variables.
Ejemplo 1: El caso básico
functionouterFunction(){let outerVariable ="I am from the outer function";functioninnerFunction(){console.log(outerVariable);}return innerFunction;}const clousureExample =outerFunction();clousureExample();// "I am from the outer function"
¿Qué pasa paso a paso?
Llamas a outerFunction(). Se crea la variable outerVariable dentro de su scope.
outerFunctionretornainnerFunction (sin ejecutarla, solo la referencia a la función).
Normalmente pensarías: "cuando outerFunction termina, outerVariable debería desaparecer, porque era una variable local de esa función".
Pero no desaparece. Porque innerFunction la "necesita" (tiene una referencia a ella en su código), JavaScript mantiene outerVariable viva en memoria, atada a innerFunction.
clousureExample ahora es innerFunction, cargando consigo ese "mochila" con outerVariable adentro.
Cuando llamas clousureExample(), aunque outerFunction ya terminó hace rato, innerFunction todavía puede leer outerVariable.
Esa "mochila" que la función se lleva es el closure.
Ejemplo 2: Estado privado y contador
functioncreateCounter(){let count =0;returnfunction(){ count++;console.log(`Current count: ${count}`);};}const counterA =createCounter();counterA();// Current count: 1counterA();// Current count: 2const counterB =createCounter();counterB();// Current count: 1
Este ejemplo es clave porque muestra dos cosas nuevas:
A) El closure no solo lee, también puede modificar la variable
Cada vez que llamas counterA(), se ejecuta count++. Esa variable count sigue viva entre llamadas — no se reinicia. El closure guarda una referencia real a la variable, no una copia congelada de su valor.
B) Cada llamada a createCounter() crea un closure NUEVO e independiente
const counterA =createCounter();// crea SU PROPIA variable "count" (empieza en 0)const counterB =createCounter();// crea OTRA variable "count", totalmente distinta (empieza en 0)
Piénsalo así: cada vez que ejecutas createCounter(), JavaScript crea una nueva "caja" con su propia count adentro, y te da una función que solo tiene llave a esa caja específica.
createCounter() llamada #1 → Caja1:{count:0} → counterA tiene la llave de la Caja1createCounter() llamada #2 → Caja2:{count:0} → counterB tiene la llave de la Caja2
Por eso counterA() dos veces da 1, 2 — pero counterB() empieza en 1 de nuevo, no en 3. Son cajas completamente separadas, aunque vengan de la misma función createCounter.
Esto es exactamente cómo se logra "estado privado" en JavaScript: count no es accesible desde afuera directamente (no puedes hacer counterA.count), solo se puede modificar a través de la función que retornó createCounter. Es una forma de encapsulamiento, similar a una variable privada en POO.
Ejemplo 3: Confirmando la independencia con parámetros
Mismo patrón: outer() se llama dos veces → dos closures independientes, cada uno con su propia copia de message (aunque en este caso message nunca cambia, cada closure técnicamente tiene la suya).
clousureA e clousureB son ambos funciones inner, pero cada una "recuerda" el message de su propia ejecución de outer(). Por eso name (el parámetro, que sí cambia en cada llamada) se combina correctamente con el message correspondiente a cada closure.
Analogía para que se te quede grabado
Imagina que outerFunction es una fábrica de mochilas. Cada vez que la llamas, la fábrica:
Mete algunas cosas dentro de una mochila (las variables locales, como count o message).
Te entrega la mochila ya empacada (la función interna).
Aunque la fábrica cierre después (la función outer termine de ejecutarse), la mochila sigue existiendo y sigue teniendo esas cosas adentro, porque tú la tienes en la mano. Cada vez que llamas a la fábrica, te da una mochila nueva, no la misma de antes.
Regla mental para resumir
Un closure ocurre cuando una función interna usa variables de una función externa, y esa función interna se "escapa" hacia afuera (se retorna, se guarda, se pasa como callback). JavaScript entonces mantiene vivas esas variables externas mientras la función interna las siga necesitando.
Tabla resumen de los 3 ejemplos
EjemploQué demuestra
outerFunction / innerFunction
El closure "recuerda" variables aunque la función externa ya terminó
createCounter
El closure puede modificar el valor, y cada llamada crea un closure independiente
outer / inner
Confirma que closures distintos no comparten memoria entre sí, cada uno tiene su propia copia.