Closures
Ya conoces el ámbito (scope): desde aquí, qué nombres son visibles. Un paso más: una función interna puede seguir usando un nombre exterior después de que termine la llamada exterior. Ese vínculo duradero es un closure.
Qué significa un closure
Se forma un closure cuando una función se crea dentro de otra y más tarde sigue alcanzando los enlaces de la exterior. La llamada exterior puede haber terminado; la interna aún «recuerda» esos nombres. No escribes la palabra closure en el código: escribes funciones anidadas y JavaScript mantiene vivos los enlaces exteriores necesarios.
Tres piezas a mirar
📊 Función exterior, enlace y función interior
| Pieza | Rol | Pista para principiantes |
|---|---|---|
| función exterior | se ejecuta una vez (o más) y a menudo devuelve una interior | la llamada de «preparación» |
| enlace exterior | un parámetro o let / const en la exterior |
el valor que la interior aún necesita |
| función interior | usa ese enlace cuando la llamas después | la función que guardas |
Si puedes señalar esas tres, explicas casi cualquier ejemplo de closure para principiantes. La sorpresa no es el anidamiento: es que el enlace exterior sigue siendo útil tras el return exterior.
function makeLine(title) {
function show() {
console.log(title);
}
show();
}
makeLine("Shop");
Durante la llamada, la interior mira hacia afuera
show no tiene un title local. La búsqueda camina hacia afuera hasta makeLine y encuentra el parámetro. Eso es ámbito anidado normal. El closure da un paso más: guarda show (o su gemela) para después, cuando makeLine ya haya vuelto.
function makeLine(title) {
return function show() {
console.log(title);
};
}
let printShop = makeLine("Shop");
printShop();
Termina la llamada exterior — la memoria permanece
makeLine("Shop") devuelve una función. Cuando llamas printShop después, aún imprime Shop. El parámetro title de esa llamada terminada sigue alcanzable. Esa captura duradera es el closure.
function makeGreeter(name) {
return function () {
return "Hello, " + name;
};
}
let hiSara = makeGreeter("Sara");
console.log(hiSara());
Las fábricas devuelven una función lista
makeGreeter es una fábrica pequeña: una llamada exterior, una función a medida de vuelta. hiSara siempre saluda a Sara porque cerró sobre ese name. Cambia el argumento de makeGreeter y obtienes otro saludador: mismo patrón, memoria nueva.
function makeCounter() {
let n = 0;
return function () {
n = n + 1;
return n;
};
}
let tick = makeCounter();
console.log(tick());
console.log(tick());
Estado casi privado con un contador
n vive en la función exterior. El código de fuera no toca n directamente: solo la función devuelta puede. La primera llamada devuelve 1, la segunda 2. El contador «recuerda» sin una variable global.
function makeCounter() {
let n = 0;
return function () {
n = n + 1;
return n;
};
}
let a = makeCounter();
let b = makeCounter();
console.log(a());
console.log(a());
console.log(b());
Cada llamada exterior tiene su memoria
a y b vienen de llamadas makeCounter() distintas, así que cada una tiene su propio n. Dos avances en a no hacen que b empiece a mitad. Los closures no comparten un saco de estado automáticamente salvo que compartas a propósito un enlace exterior.
Mostrar un valor cerrado en la página
Crea un saludador con la fábrica, llámalo una vez y pon la cadena devuelta en un párrafo.
<!DOCTYPE html>
<html>
<head>
<title>closures — page</title>
</head>
<body>
<p id="msg">…</p>
<script>
function makeGreeter(name) {
return function () {
return "Hello, " + name;
};
}
let hi = makeGreeter("Omar");
let box = document.getElementById("msg");
box.textContent = hi();
</script>
</body>
</html>
El párrafo muestra Hello, Omar. La llamada exterior terminó; hi aún conoce name. Cambia solo la cadena pasada a makeGreeter, actualiza y lee la nueva línea. Siguiente: objetos — valores relacionados bajo un solo nombre.
Práctica
- Escribe una función que devuelva una interior que registre un parámetro exterior.
- Guarda esa función devuelta y llámala tras terminar la llamada exterior.
- Crea
makeGreeter("Lina")y registra la cadena que devuelve. - Crea un contador; llámalo dos veces y confirma
1y luego2. - Crea dos contadores; avanza solo el primero dos veces y comprueba que el segundo empieza en
1. - En la demo HTML cambia solo el argumento del nombre, actualiza y lee el párrafo.
Tropezones frecuentes
- Suponer que los locales exteriores desaparecen al instante del
return— la interior aún puede verlos - Esperar que cada
makeCounter()comparta un solon— cada llamada suele tener su memoria - Creer que «closure» significa solo la palabra
return—returnpuede devolver la interior, pero la memoria es el enlace cerrado - Poner todo valor recordado en el objeto global «para simplificar»
- Esperar aquí la lección completa de objetos — agrupar propiedades bajo un valor es la página siguiente
Resumen
- Un closure permite que una función interior siga usando nombres exteriores tras la llamada exterior
- Escribes funciones anidadas; JavaScript mantiene vivos los enlaces necesarios
- Las fábricas devuelven una función a medida que recuerda los valores de preparación
- Los contadores ocultan un
nprivado tras la función devuelta - Llamadas exteriores separadas suelen significar memorias separadas
- La página puede mostrar una cadena producida por un nombre cerrado
- Siguiente: objetos — valores relacionados bajo un nombre
🧠 Pon a Prueba tu Conocimiento
Pon a Prueba tu Conocimiento
Ponte a prueba con este cuestionario interactivo y descubre qué tan bien entiendes el tema
📝 Instrucciones
- Lee cada pregunta cuidadosamente
- Selecciona la mejor respuesta para cada pregunta
- Puedes repetir el quiz tantas veces como quieras
- Tu progreso se mostrará en la parte superior