JavaScript

Closures em JavaScript: Escopo Léxico e Funções de Primeira Classe na Prática

7 min de leitura

Closures em JavaScript: Escopo Léxico e Funções de Primeira Classe na Prática

Escopo Léxico: O Alicerce das Closures 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 posição do código no arquivo, 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. Neste exemplo, acessa variáveis de três níveis diferentes: seu próprio escopo, o escopo de 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 shadowing quando uma variável interna tem o mesmo nome de uma externa — a interna prevalece. Closures: Capturando o Escopo 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

<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 &quot;lembra&quot; 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 = &quot;Sou global&quot;;

function externa() {

const doEscopo = &quot;Sou do escopo da função externa&quot;;

function interna() {

const local = &quot;Sou local&quot;;

console.log(local); // &quot;Sou local&quot;

console.log(doEscopo); // &quot;Sou do escopo da função externa&quot;

console.log(global); // &quot;Sou global&quot;

}

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 &quot;captura&quot; 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(&quot;João&quot;, 30);

console.log(joao.getNome()); // &quot;João&quot;

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()); // [&quot;2 + 3 = 5&quot;]

// 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 &lt; 3; i++) {

funcs.push(() =&gt; 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&#039;t Know JS - Scope &amp; Closures</a></li>

</ul>

Comentários

Mais em JavaScript

Boas Práticas de Proxy e Reflect em JavaScript: Interceptando Operações em Objetos para Times Ágeis
Boas Práticas de Proxy e Reflect em JavaScript: Interceptando Operações em Objetos para Times Ágeis

Introdução: Por que Proxy e Reflect Importam para Times Ágeis Proxy e Reflect...

Boas Práticas de Promises em JavaScript: then, catch, finally e Encadeamento para Times Ágeis
Boas Práticas de Promises em JavaScript: then, catch, finally e Encadeamento para Times Ágeis

O que é uma Promise? Uma Promise é um objeto JavaScript que representa o resu...

Como Usar Metaprogramação em JavaScript: Object.defineProperty e Decorators em Produção
Como Usar Metaprogramação em JavaScript: Object.defineProperty e Decorators em Produção

Object.defineProperty: Controle Fino sobre Propriedades Object.defineProperty...