<h2>Escopo Léxico: O Alicerce das Closures</h2>
<p>O escopo léxico é a regra fundamental que governa como as variáveis são resolvidas em JavaScript. Ele significa que o escopo é determinado pela <strong>posição do código no arquivo</strong>, não por onde a função é chamada. Quando você declara uma função, ela "lembra" do ambiente em que foi definida, criando uma cadeia de escopos que pode ser consultada em tempo de execução.</p>
<pre><code class="language-javascript">const global = "Sou global";
function externa() {
const doEscopo = "Sou do escopo da função externa";
function interna() {
const local = "Sou local";
console.log(local); // "Sou local"
console.log(doEscopo); // "Sou do escopo da função externa"
console.log(global); // "Sou global"
}
interna();
}
externa();</code></pre>
<p>Neste exemplo, <code>interna()</code> acessa variáveis de três níveis diferentes: seu próprio escopo, o escopo de <code>externa()</code> e o escopo global. O JavaScript busca essas variáveis seguindo a cadeia de escopos, sempre começando pelo mais próximo. Essa característica é chamada de <strong>shadowing</strong> quando uma variável interna tem o mesmo nome de uma externa — a interna prevalece.</p>
<h2>Closures: Capturando o Escopo</h2>
<p>Uma closure é uma função que "captura" variáveis do seu escopo envolvente e as mantém vivas, mesmo após a função externa ter terminado sua execução. Contrário ao que muitos pensam, closures não são um recurso especial — elas são o comportamento <strong>padrão</strong> de toda função em JavaScript.</p>
<pre><code class="language-javascript">function contador() {
let count = 0;
return function() {
count++;
return count;
};
}
const incrementar = contador();
console.log(incrementar()); // 1
console.log(incrementar()); // 2
console.log(incrementar()); // 3</code></pre>
<p>Aqui, a função retornada é uma closure que captura a variável <code>count</code>. Mesmo após <code>contador()</code> ter terminado, a variável <code>count</code> não é descartada pelo garbage collector — ela continua viva enquanto a função retornada existir. Cada chamada a <code>incrementar()</code> modifica e retorna o novo valor de <code>count</code>. Se você criar outra variável com <code>contador()</code>, ela terá sua própria instância isolada de <code>count</code>.</p>
<pre><code class="language-javascript">const contador1 = contador();
const contador2 = contador();
console.log(contador1()); // 1
console.log(contador1()); // 2
console.log(contador2()); // 1 — nova instância!</code></pre>
<h2>Funções de Primeira Classe e Padrões Práticos</h2>
<p>Em JavaScript, funções são cidadãs de primeira classe: podem ser atribuídas a variáveis, passadas como argumentos e retornadas como valores. Essa característica, combinada com closures, permite padrões poderosos como factory functions, decorators e módulos.</p>
<h3>Factory Functions</h3>
<p>Factory functions retornam novos objetos, frequentemente usando closures para encapsular dados privados:</p>
<pre><code class="language-javascript">function criarPessoa(nome, idade) {
// Dados privados
let _idade = idade;
return {
getNome() { return nome; },
getIdade() { return _idade; },
fazerAniversario() { _idade++; }
};
}
const joao = criarPessoa("João", 30);
console.log(joao.getNome()); // "João"
console.log(joao.getIdade()); // 30
joao.fazerAniversario();
console.log(joao.getIdade()); // 31</code></pre>
<p>Neste padrão, <code>_idade</code> é privada — só pode ser acessada através dos métodos retornados. Isso é encapsulamento real sem necessidade de classes.</p>
<h3>Decorators</h3>
<p>Decorators usam closures para envolver funções e modificar seu comportamento:</p>
<pre><code class="language-javascript">function logger(funcao) {
return function(...args) {
console.log(Chamando ${funcao.name} com:, args);
const resultado = funcao.apply(this, args);
console.log(Resultado:, resultado);
return resultado;
};
}
function somar(a, b) {
return a + b;
}
const somarComLog = logger(somar);
somarComLog(5, 3);
// Chamando somar com: [5, 3]
// Resultado: 8</code></pre>
<p>O decorator <code>logger</code> retorna uma closure que captura a função original, permitindo executar código antes e depois dela. Esse padrão é usado extensivamente em frameworks modernos.</p>
<h3>Padrão de Módulo</h3>
<p>Closures são a base do padrão de módulo, que cria espaços privados sem poluir o escopo global:</p>
<pre><code class="language-javascript">const calculadora = (function() {
// Dados e funções privadas
const historico = [];
function registrar(operacao) {
historico.push(operacao);
}
// API pública
return {
somar(a, b) {
const resultado = a + b;
registrar(${a} + ${b} = ${resultado});
return resultado;
},
getHistorico() {
return [...historico];
}
};
})();
console.log(calculadora.somar(2, 3)); // 5
console.log(calculadora.getHistorico()); // ["2 + 3 = 5"]
// console.log(calculadora.historico); // undefined — privado!</code></pre>
<p>A função anônima auto-executada cria um escopo privado. Apenas os métodos retornados têm acesso a <code>historico</code> e <code>registrar</code>, implementando verdadeiro encapsulamento.</p>
<h2>Armadilhas Comuns e Boas Práticas</h2>
<p>Um erro frequente ocorre em loops quando você tenta capturar valores mutáveis. No exemplo abaixo, todas as closures compartilham a mesma variável <code>i</code>:</p>
<pre><code class="language-javascript">// ❌ Errado
const funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(() => console.log(i));
}
funcs[0](); // 3
funcs[1](); // 3
funcs[2](); // 3</code></pre>
<p>Ao invocar as funções, <code>i</code> já vale 3. A solução é usar <code>let</code> ou criar uma closure adicional:</p>
<pre><code class="language-javascript"></code></pre>
<p>Com <code>let</code>, cada iteração cria um novo escopo, capturando uma nova instância de <code>i</code>. Com IIFE, passamos <code>i</code> como argumento, criando uma closure sobre um parâmetro que não muda.</p>
<h2>Conclusão</h2>
<p>Closures são o mecanismo fundamental que permite encapsulamento, abstrações seguras e padrões de design poderosos em JavaScript. O escopo léxico garante que funções sempre acessem o ambiente correto, independente de onde são executadas. Quando você domina closures e funções de primeira classe, pode criar código mais modular, testável e mantível — desde factory functions até decorators e módulos auto-contidos. A chave é entender que <strong>toda função em JavaScript é uma closure</strong>, e aprender a usá-las intencionalmente para resolver problemas de forma elegante.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Closures" target="_blank" rel="noopener noreferrer">MDN Web Docs - Closures</a></li>
<li><a href="https://developer.mozilla.org/pt-BR/docs/Glossary/Scope" target="_blank" rel="noopener noreferrer">MDN Web Docs - Escopo</a></li>
<li><a href="https://javascript.info/closure" target="_blank" rel="noopener noreferrer">JavaScript.info - Variable Scope</a></li>
<li><a href="https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/scope-closures" target="_blank" rel="noopener noreferrer">You Don't Know JS - Scope & Closures</a></li>
</ul>