Escopo de Variáveis em JavaScript
Entenda o escopo de variáveis em JavaScript: escopo global, de função e de bloco, hoisting, TDZ e como closures funcionam.
Escopo é a parte de um programa onde uma variável é visível e pode ser usada. Entender o escopo permite prever a qual valor um nome se refere, evitar conflitos acidentais entre variáveis e compreender por que uma variável está ou não disponível em determinado ponto. Este guia explica os tipos de escopo que o JavaScript possui, como funções aninhadas acessam os escopos ao redor, como o var difere do let/const, e como tudo isso leva naturalmente às closures.
Os três tipos de escopo
O JavaScript determina a visibilidade das variáveis com base em onde a variável é declarada no código-fonte — isso é chamado de escopo léxico (ou estático). Existem três níveis:
- Escopo global — declarado fora de qualquer função ou bloco. Visível em todo lugar.
- Escopo de função — declarado dentro de uma função. Visível apenas dentro dessa função (é assim que o
varfunciona). - Escopo de bloco — declarado com
letouconstdentro de um bloco{ ... }(umif, umfor, ou mesmo um{}simples). Visível apenas dentro desse bloco.
Escopo global
Uma variável declarada no nível mais alto de um script é global: toda função e bloco pode lê-la e escrevê-la.
Variáveis globais são convenientes, mas arriscadas: qualquer parte do programa pode alterá-las, e dois trechos de código independentes podem usar o mesmo nome e sobrescrever um ao outro. Mantenha o namespace global pequeno.
Escopo de função
Uma variável declarada dentro de uma função existe apenas enquanto essa função está em execução e é invisível do lado de fora.
O try...catch permite que o exemplo continue executando para que você possa ver a mensagem de erro em vez de o script simplesmente parar.
Escopo de bloco
let e const têm escopo no bloco delimitador mais próximo, não na função inteira. Uma variável declarada dentro de um bloco if ou for deixa de existir quando o bloco termina.
Como funções aninhadas enxergam variáveis externas
Quando você aninha funções, a função interna pode ler variáveis de todos os escopos que a envolvem — o seu próprio, o da função externa e o escopo global. Essa cadeia de escopos acessíveis é chamada de ambiente léxico (ou cadeia de escopos).
Quando o JavaScript procura um nome, começa no escopo atual e percorre para fora até encontrar a variável. Se chegar ao escopo global sem encontrá-la, você receberá um ReferenceError.
A busca ocorre apenas para fora, nunca para dentro — outer() não pode ver innerVar. Esse é exatamente o mecanismo que faz as closures funcionarem: uma função interna mantém acesso às variáveis externas mesmo após o retorno da função externa.
var vs let e const
As regras de escopo diferem dependendo de como você declara uma variável. var tem escopo de função e ignora blocos, enquanto let e const têm escopo de bloco. Essa é uma das fontes mais comuns de bugs em código mais antigo.
A armadilha clássica é um loop que cria callbacks. Com var há uma única variável compartilhada; com let cada iteração tem sua própria ligação:
Para uma análise mais aprofundada das particularidades do var — incluindo hoisting e a ausência de escopo de bloco — veja o antigo "var".
Hoisting e a Zona Morta Temporal
As declarações são processadas antes da execução do código. Uma declaração var é içada (hoisted) e inicializada como undefined, então lê-la antes da atribuição resulta em undefined em vez de um erro. let e const também sofrem hoisting, mas permanecem em uma Zona Morta Temporal (TDZ) — inutilizáveis até que a linha que as declara seja executada.
Boas práticas
- Prefira
const, depoislet, evitevar. O escopo de bloco é mais previsível e evita vazamentos acidentais e a armadilha de loop com callbacks mostrada acima. - Mantenha as variáveis no escopo mais restrito possível. Declare dentro do bloco ou função que as precisa, em vez de no nível superior.
- Minimize as variáveis globais. Menos globais significa menos conflitos de nomes e menos valores que qualquer código pode alterar silenciosamente.
- Declare antes de usar. Mesmo que o hoisting exista, depender dele torna o código mais difícil de ler.
Conclusão
O escopo controla onde cada variável é visível: global, de função ou de bloco. Funções aninhadas formam um ambiente léxico que permite ao código interno alcançar para fora pela cadeia de escopos — a base das closures. Escolher let/const em vez de var garante um escopo de bloco confiável e evita surpresas com hoisting. Em seguida, estude como as funções capturam seu entorno em Closures em JavaScript e como as funções retornadas se comportam em expressões de função.