Closures
Já conhece o âmbito (scope): daqui, quais nomes são visíveis. Mais um passo: uma função interna pode continuar a usar um nome exterior depois de a chamada exterior terminar. Essa ligação duradoura é um closure.
O que um closure significa
Forma-se um closure quando uma função é criada dentro de outra e mais tarde ainda alcança as ligações da exterior. A chamada exterior pode ter acabado; a interna ainda «lembra» esses nomes. Não escreve a palavra closure no código — escreve funções aninhadas e o JavaScript mantém vivas as ligações exteriores necessárias.
Três peças a observar
📊 Função exterior, ligação e função interior
| Peça | Papel | Pista para iniciantes |
|---|---|---|
| função exterior | corre uma vez (ou mais) e muitas vezes devolve uma interior | a chamada de «preparação» |
| ligação exterior | um parâmetro ou let / const na exterior |
o valor de que a interior ainda precisa |
| função interior | usa essa ligação quando a chama mais tarde | a função que guarda |
Se conseguir apontar estas três, explica quase qualquer exemplo de closure para iniciantes. A surpresa não é o aninhamento — é que a ligação exterior continua útil depois do return exterior.
function makeLine(title) {
function show() {
console.log(title);
}
show();
}
makeLine("Shop");
Durante a chamada, a interior olha para fora
show não tem um title local. A procura caminha para fora até makeLine e encontra o parâmetro. Isso é âmbito aninhado normal. Os closures vão mais longe: guarde show (ou a gémea) para depois, quando makeLine já tiver regressado.
function makeLine(title) {
return function show() {
console.log(title);
};
}
let printShop = makeLine("Shop");
printShop();
A chamada exterior acaba — a memória fica
makeLine("Shop") devolve uma função. Quando chama printShop mais tarde, ainda imprime Shop. O parâmetro title dessa chamada terminada continua acessível. Essa captura duradoura é o closure.
function makeGreeter(name) {
return function () {
return "Hello, " + name;
};
}
let hiSara = makeGreeter("Sara");
console.log(hiSara());
As fábricas devolvem uma função pronta
makeGreeter é uma fábrica pequena: uma chamada exterior, uma função à medida de volta. hiSara cumprimenta sempre a Sara porque fechou sobre esse name. Mude o argumento de makeGreeter e obtém outro cumprimentador — mesmo padrão, memória nova.
function makeCounter() {
let n = 0;
return function () {
n = n + 1;
return n;
};
}
let tick = makeCounter();
console.log(tick());
console.log(tick());
Estado quase privado com um contador
n vive na função exterior. O código de fora não toca em n diretamente — só a função devolvida pode. A primeira chamada devolve 1, a segunda 2. O contador «lembra» sem variável 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 chamada exterior tem a sua memória
a e b vieram de chamadas makeCounter() separadas, por isso cada uma tem o seu n. Dois passos em a não fazem b começar a meio. Os closures não partilham automaticamente um saco de estado a menos que partilhe de propósito uma ligação exterior.
Mostrar um valor fechado na página
Construa um cumprimentador com a fábrica, chame-o uma vez e coloque a string devolvida num parágrafo.
<!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>
O parágrafo mostra Hello, Omar. A chamada exterior terminou; hi ainda conhece name. Mude só a string passada a makeGreeter, atualize e leia a nova linha. Seguinte: objetos — valores relacionados sob um nome.
Prática
- Escreva uma função que devolva uma interior que registe um parâmetro exterior.
- Guarde essa função devolvida e chame-a depois de a chamada exterior terminar.
- Construa
makeGreeter("Lina")e registe a string que devolve. - Crie um contador; chame-o duas vezes e confirme
1depois2. - Crie dois contadores; avance só o primeiro duas vezes e verifique que o segundo começa em
1. - Na demo HTML mude só o argumento do nome, atualize e leia o parágrafo.
Tropeços frequentes
- Assumir que os locais exteriores desaparecem no instante do
return— a interior ainda os pode ver - Esperar que cada
makeCounter()partilhe um únicon— cada chamada costuma ter a sua memória - Pensar que «closure» significa só a palavra
return—returnpode devolver a interior, mas a memória é a ligação fechada - Colocar todo o valor lembrado no objeto global «para simplificar»
- Esperar aqui a lição completa de objetos — agrupar propriedades sob um valor é a página seguinte
Resumo
- Um closure deixa uma função interna usar nomes exteriores depois de a chamada exterior acabar
- Escreve funções aninhadas; o JavaScript mantém vivas as ligações necessárias
- As fábricas devolvem uma função à medida que lembra os valores de preparação
- Os contadores escondem um
nprivado atrás da função devolvida - Chamadas exteriores separadas costumam significar memórias separadas
- A página pode mostrar uma string produzida por um nome fechado
- Seguinte: objetos — valores relacionados sob um nome
🧠 Teste Seu Conhecimento
Teste Seu Conhecimento
Desafie-se com este questionário interativo e veja o quão bem você entende o tópico
📝 Instruções
- Leia cada pergunta cuidadosamente
- Selecione a melhor resposta para cada pergunta
- Você pode refazer o quiz quantas vezes quiser
- Seu progresso será mostrado no topo