O que é closure e como funciona em linguagens modernas?
Closure é uma função que mantém acesso ao escopo onde foi criada, mesmo depois que esse escopo deixou de existir. Em vez de perder as variáveis externas quando a função termina, a closure as 'captura' e mantém vivas. Isso permite criar estados privados, callbacks com contexto e fábricas de funções. A base está no escopo léxico: o local onde a função é definida determina quais variáveis ela enxerga.
Como o escopo léxico se relaciona com closures?
O escopo léxico é a regra que define onde uma variável pode ser acessada com base na posição física do código. Quando você aninha uma função dentro de outra, a função interna tem acesso às variáveis da externa. Se a externa retorna a interna, a interna leva consigo uma referência ao escopo da externa. Essa referência é a closure.
Em JavaScript, por exemplo:
function criarContador() { let count = 0; return function() { count++; return count; }; } const contador = criarContador(); console.log(contador()); // 1 console.log(contador()); // 2
A função retornada acessa count mesmo após criarContador ter sido executada. O motor da linguagem mantém o ambiente léxico vivo enquanto a closure existir. Em Python, o mecanismo é similar, mas exige a palavra-chave nonlocal para modificar variáveis externas:
def criar_contador(): count = 0 def incrementar(): nonlocal count count += 1 return count return incrementar
A diferença está na forma como cada linguagem lida com a mutabilidade do escopo capturado.
Quais linguagens modernas usam closures?
JavaScript, Python, Ruby, Swift, Kotlin, Rust e C# implementam closures. Até linguagens compiladas como C++ oferecem o recurso via lambdas com captura explícita ([&], [=]). A adoção é ampla porque closures resolvem problemas de composição e encapsulamento sem exigir classes ou objetos.
Em Rust, por exemplo, closures capturam variáveis por referência, mutação ou movimento, e o compilador verifica se o acesso é seguro. Já em Java, a partir da versão 8, expressões lambda capturam variáveis efetivamente finais, o que limita mutações mas garante consistência.
Como closures são usadas na prática?
Closures aparecem em callbacks, manipuladores de eventos, funções de alta ordem e padrões de projeto como módulo e curry. Um exemplo comum é a criação de funções especializadas:
function multiplicador(fator) { return function(numero) { return numero * fator; }; } const dobrar = multiplicador(2); console.log(dobrar(5)); // 10
Aqui, multiplicador gera uma closure que 'lembra' o fator. Isso evita repetição e mantém o código expressivo. Em React, closures são usadas em hooks como useState e useEffect, mas exigem cuidado com dependências para não capturar valores desatualizados.
Quais os riscos e limitações das closures?
O primeiro risco é o vazamento de memória. Como a closure mantém referências a variáveis externas, objetos grandes podem permanecer na memória enquanto a função existir. Em aplicações de longa duração, isso pode degradar performance.
Outro ponto é a legibilidade. Closures aninhadas em excesso tornam o fluxo difícil de seguir. O contraponto é que, quando bem usadas, eliminam a necessidade de variáveis globais e reduzem efeitos colaterais.
Há também a questão do this em JavaScript. Funções tradicionais criam seu próprio this, enquanto arrow functions capturam o this do escopo léxico. Isso muda o comportamento em callbacks e é uma fonte comum de bugs.
Como closures se comparam a objetos e classes?
Closures oferecem encapsulamento sem a sintaxe de classes. Em vez de criar uma classe com métodos, você retorna um objeto com funções que compartilham variáveis privadas. A diferença é que closures são mais leves e diretas para estados simples, enquanto classes são melhores para estruturas complexas com herança e polimorfismo.
Em Python, por exemplo, closures podem substituir classes em casos de funções fábrica. Já em JavaScript, o padrão módulo com closures foi amplamente usado antes da popularização dos módulos ES6.
O que ainda falta provar sobre closures?
A promessa é código mais limpo e modular. A entrega depende do contexto. Em projetos pequenos, closures podem adicionar complexidade desnecessária. Em sistemas grandes, o ganho de encapsulamento é real, mas exige disciplina para não criar dependências ocultas.
A pergunta certa é outra: sua equipe entende o custo de memória e o comportamento de this? Se a resposta for não, closures viram fonte de bugs sutis. A documentação oficial do MDN e as especificações da ECMAScript são o ponto de partida para dominar o conceito.
Resumo prático
Closure é a combinação de uma função com o escopo léxico onde foi criada. Permite acessar variáveis externas mesmo após o escopo original terminar. Útil para callbacks, estados privados e funções fábrica. Cuidado com vazamentos de memória e comportamento de this. Entender closures é essencial para escrever código moderno em JavaScript, Python e além.
FAQ
O que é closure em JavaScript?
Closure é uma função que mantém acesso ao escopo onde foi definida, mesmo depois que esse escopo deixou de existir. Em JavaScript, isso ocorre porque a função interna captura o ambiente léxico da função externa. Exemplo: um contador que preserva o valor entre chamadas.
Como closures funcionam com variáveis de escopo?
Closures capturam variáveis por referência, não por valor. Isso significa que se a variável externa mudar, a closure verá o novo valor. Em loops, isso pode causar comportamentos inesperados se não forem usadas declarações let ou const para criar escopos por iteração.
Qual a diferença entre closure e escopo léxico?
Escopo léxico é a regra que define onde variáveis são acessíveis com base na posição do código. Closure é o mecanismo que permite a uma função acessar esse escopo mesmo após a função externa ter retornado. O escopo léxico é a base; a closure é a consequência.
Closures podem causar vazamento de memória?
Sim. Como a closure mantém referências a variáveis externas, objetos grandes podem permanecer na memória enquanto a função existir. Em aplicações de longa duração, isso pode levar a consumo excessivo de memória. É importante liberar referências quando não forem mais necessárias.
Como usar closures em Python?
Em Python, closures são criadas com funções aninhadas. Para modificar variáveis externas, use nonlocal. Exemplo: uma função que incrementa um contador interno. Python também oferece functools.partial para criar closures de forma mais concisa.
Closures são a mesma coisa que funções anônimas?
Não. Funções anônimas (lambdas) são apenas funções sem nome. Closures são funções que capturam o escopo léxico. Toda closure pode ser uma função anônima, mas nem toda função anônima é uma closure. A diferença está na captura de variáveis externas.