

Junior Alves
Senior Developer
Foto: Unsplash
Atualizado: 3 de julho de 2025 às 08:58
Leitura: 7 minutos de leitura
Criado: 3 de julho de 2025
Lexical Environment Explicado
Seu código React e Node.js depende disso (e você precisa entender)
Introdução
Bora falar de um código que, muito provavelmente, você já escreveu ou viu dezenas de vezes? Imagine a cena: você está criando uma lista dinâmica de itens a partir de um array de dados, podem ser produtos, tarefas, posts, o que for.
Para cada item, você adiciona um botão de "Excluir".
const products = [
{ id: 'p1', name: 'Caneca de Café' },
{ id: 'p2', name: 'Mousepad Ergonômico' },
{ id: 'p3', name: 'Teclado Mecânico' }
];
const productListElement = document.getElementById('product-list');
products.forEach((product) => {
const itemElement = document.createElement('li');
const deleteButton = document.createElement('button');
itemElement.textContent = product.name;
deleteButton.textContent = 'Excluir';
// A "mágica" acontece aqui!
deleteButton.addEventListener('click', () => {
console.log(`Excluindo produto com ID: ${product.id}`);
// Lógica para remover o item da API e do DOM...
});
itemElement.appendChild(deleteButton);
productListElement.appendChild(itemElement);
});
Versão em vídeo sobre esse conteúdo
Escopo (Scope) - As Fronteiras do seu Código
Antes de entendermos a "memória" das funções, precisamos primeiro entender onde as variáveis "vivem". É aqui que entra o conceito de Escopo
.
Pense no escopo como a jurisdição ou a "bolha de visibilidade" de uma variável. Se uma variável é declarada dentro de uma determinada bolha, ela só é naturalmente acessível ali dentro e em bolhas filhas.
No Javascript, temos principalmente três tipos de escopo com os quais lidamos:
Escopo Global: Variáveis declaradas fora de qualquer função ou bloco. Elas são o "patrimônio público" do seu código, acessíveis de qualquer lugar. É uma prática recomendada evitar ao máximo poluir esse escopo.
Escopo de Função: Cada função cria sua própria "bolha". Variáveis declaradas com var
, let
ou const
dentro de uma função pertencem a ela e não podem ser acessadas de fora.
Escopo de Bloco: Introduzido com let
e const
no ES6. Qualquer par de chaves (em um if, for, while ou mesmo solto no código) cria uma bolha de escopo ainda menor.
O escopo é o que nos impede de ter colisões de nomes de variáveis o tempo todo e nos ajuda a manter o código organizado. É um conceito fundamental.
Ok, simples, certo? Mas o que acontece quando estamos dentro de uma bolha e precisamos de uma variável que está na bolha externa?
Scope Chain - A Busca Pela Variável
Nenhuma função é uma ilha. Frequentemente, uma função precisa acessar variáveis de seu escopo pai. É aqui que entra a Scope Chain
(ou Corrente de Escopos).
Quando o Javascript precisa encontrar o valor de uma variável, ele segue uma regra muito simples:
- Procure no dicionário local: Ele primeiro olha no escopo atual (a bolha mais interna). Encontrou? Ótimo, use o valor.
- Suba um nível: Não encontrou? Ele "sobe" para o escopo pai (a bolha que contém a bolha atual) e repete a busca por lá.
- Continue subindo: Esse processo continua, subindo na cadeia de escopos, até que a variável seja encontrada ou até que se chegue ao escopo global.
- Erro de Referência: Se a busca chegar ao escopo global e a variável ainda não for encontrada, o Javascript desiste e lança um ReferenceError.
Essa busca em cadeia, do ambiente mais interno para o mais externo, é a Scope Chain
. Ela explica como funções aninhadas conseguem usar variáveis de suas "mães".
Isso nos leva diretamente à resposta do nosso exemplo inicial.
Closures - A "Mochila" de Memória do Javascript
Agora que entendemos que uma função pode acessar variáveis de seu escopo pai, a grande questão do nosso exemplo permanece: como ela faz isso se o escopo pai (a iteração do forEach) já "desapareceu"?
A resposta é que ele não desapareceu.
Quando uma função é criada, ela não apenas "sabe" qual é seu escopo pai; ela mantém um link vivo para ele. Esse link, junto com as variáveis daquele ambiente que ela precisa, é o que chamamos de Closure.
Pense nisso como uma mochila. Quando a nossa função de callback do addEventListener
é criada, o Javascript dá a ela uma mochila. Dentro dessa mochila, ele coloca referências para todas as variáveis do escopo de criação que a função utiliza.
products.forEach((product) => {
// --- Início da "bolha" da iteração ---
// A variável 'product' existe aqui.
deleteButton.addEventListener('click', () => {
// Esta função é criada aqui DENTRO.
// Ela "fecha" (closes over) a variável 'product' da sua iteração.
// Ela coloca 'product' em sua "mochila".
console.log(`Excluindo produto com ID: ${product.id}`);
});
// --- Fim da "bolha" da iteração ---
});
Para cada uma das três iterações do loop, um novo escopo é criado. Em cada um desses escopos, uma nova função de callback é criada. E cada uma dessas três funções de callback cria sua própria Closure
, cada uma carregando em sua "mochila" uma referência para a variável product daquela iteração específica.
É por isso que o Garbage Collector
(o coletor de lixo do JS) não limpa a variável product da memória. Ele vê que, embora a iteração do loop tenha terminado, existe uma função (o callback) que ainda está "viva" e segurando uma referência para aquela variável em sua "mochila".
Agora a mágica começa a parecer mais com engenharia, certo? Mas qual é a estrutura de dados que o motor do JS usa para gerenciar tudo isso?
Lexical Environment - O Coração de Tudo
Finalmente, chegamos à peça central do quebra-cabeça. Os conceitos de Escopo
, Scope Chain
e Closures
são, na verdade, os resultados visíveis de uma estrutura interna definida na especificação do Javascript: o Lexical Environment
.
Pense no Lexical Environment como o "dicionário interno" que mencionamos antes, mas de forma mais técnica. É um objeto interno que o motor do JS cria para cada escopo. Esse objeto tem duas partes principais:
- Environment Record (Registro do Ambiente): É o armazenamento de fato, o objeto que mapeia os identificadores (nomes de variáveis e funções) para seus valores. Quando você escreve
let product = ...
, uma entrada para product é criada neste registro. - Reference to the Outer Environment (Referência ao Ambiente Externo): É simplesmente um link para o Lexical Environment do escopo pai. Para o escopo global, essa referência é null, pois ele é o topo da cadeia.
Agora, vamos amarrar tudo:
Escopo
é o conceito abstrato. O Lexical Environment
é a sua implementação concreta. Cada escopo tem um.
A Scope Chain
é, na verdade, uma lista encadeada de Lexical Environments, conectados pela Reference to the Outer Environment
. A busca por uma variável é uma travessia por essa lista.
Uma Closure
é a combinação de uma função e a referência ao seu Lexical Environment de criação. A "mochila" é o Lexical Environment que a função carrega consigo. É por isso que ela "lembra": ela mantém um link para o dicionário onde suas variáveis nasceram.
No nosso exemplo do forEach, a cada iteração, um novo Lexical Environment é criado. A função de callback anônima, ao ser criada, tem sua Reference to the Outer Environment apontada para esse ambiente específico da iteração, capturando para sempre a versão correta de product.
Testando seu entendimento
Conclusão
O Lexical Environment
é a estrutura de dados, a Scope Chain
é o processo de busca através dessas estruturas, e a Closure
é o fenômeno poderoso que observamos como resultado.
Entender isso é fundamental, pois impacta diretamente como você escreve e debuga seu código, seja para evitar "stale state" em hooks do React, para criar módulos com estado privado ou simplesmente para entender por que seu event listener funciona como o esperado.
Curtiu o artigo? Deixe seu feedback, vai ajudar bastante!
Agradeço por ter lido até aqui, grande abraço e até a próxima.
Curtiu? Compartilhe esse post: