Carregando...

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.

Função interior lê um nome exterior

javascript
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.

Manter a função interior após return

javascript
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.

Pequena fábrica de saudação

javascript
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.

Contador que lembra

javascript
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.

Dois contadores, duas memórias

javascript
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.

Demo de página com closure

html
<!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

  1. Escreva uma função que devolva uma interior que registe um parâmetro exterior.
  2. Guarde essa função devolvida e chame-a depois de a chamada exterior terminar.
  3. Construa makeGreeter("Lina") e registe a string que devolve.
  4. Crie um contador; chame-o duas vezes e confirme 1 depois 2.
  5. Crie dois contadores; avance só o primeiro duas vezes e verifique que o segundo começa em 1.
  6. 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 único n — cada chamada costuma ter a sua memória
  • Pensar que «closure» significa só a palavra return — return pode 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 n privado 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

Pronto para Começar

Teste Seu Conhecimento

Desafie-se com este questionário interativo e veja o quão bem você entende o tópico

❓
8
Perguntas
🎯
70%
Para Passar
♾️
∞
Tempo
🔄
∞
Tentativas

📝 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