Artigo original: What is the Temporal Dead Zone (TDZ) in JavaScript?
Eu imagino que Zona Morta Temporal (em inglês, Temporal Dead Zone ou TDZ) pareça uma expressão saída de uma série de ficção científica. No entanto, é útil entender o significado dos termos e conceitos com os quais você trabalha diariamente (ou sobre os quais deseja aprender a respeito).
Prepare-se, então, porque as coisas ficarão bastante complicadas.
Você sabia que, em JavaScript, podemos adicionar chaves – { }
– para adicionar um nível a mais de escopo onde quisermos?
Quem quiser, pode, tranquilamente, fazer o seguinte:
{ { { { { { var loucuraPura = true } } } } } }
Incluí esse detalhe para garantir que os exemplos a seguir façam sentido (já que eu não queria dar como certo que todos sabem a respeito disso).
Antes da ES6, não havia outra maneira de declarar variáveis que não fosse com a palavra-chave var
. A ES6, porém, nos trouxe let
e const
.
As declarações de let
e const
têm escopo de bloco, o que significa que são acessíveis apenas dentro das chaves {}
que as cercam. var
, por outro lado, não tem essa restrição.
Aqui temos um exemplo:
let idadeDoBebe = 1;
let deAniversario = true;
if (deAniversario) {
let idadeDoBebe = 2;
}
console.log(idadeDoBebe); // O resultado é 1. Por quê?
O que ocorreu acima tem a ver com a nova declaração de idadeDoBebe
como sendo 2, disponível apenas dentro do bloco da instrução if
. Para além da instrução, é usada a idadeDoBebe
de fora do bloco. Consegue perceber que são duas variáveis diferentes, apesar do mesmo nome?
No entanto, a declaração com var
não tem escopo de bloco:
var idadeDoBebe = 1;
var deAniversario = true;
if (deAniversario) {
var idadeDoBebe = 2;
}
console.log(idadeDoBebe); // Aqui, o resultado é 2
A diferença destacável aqui entre let
/ const
e var
está no fato de que, se você acessar var
antes de ela ser declarada, ela tem o valor undefined
. Se, no entanto, você fizer o mesmo para let
e const
, terá o chamado ReferenceError
.
console.log(varNumero); // undefined
console.log(letNumero); // Não aparece no console e é lançado um erro dizendo que ReferenceError letNumero não é definido
var varNumero = 1;
let letNumero = 1;
Esse erro é lançado devido à Zona Morta Temporal.
A Zona Morta Temporal explicada
O que é a Zona Morta Temporal? O termo serve para descrever o estado onde variáveis não são alcançáveis. Elas estão no escopo, mas não são declaradas.
As variáveis let
e const
existem na Zona Morta Temporal desde o início do escopo que as cerca até serem declaradas.
É possível dizer que as variáveis existem na Zona Morta Temporal do local ao qual elas estão vinculadas (quando a variável fica associada ao escopo em que está) até ser declarada (quando é reservado um nome na memória para aquela variável).
{
// Esta é a zona morta temporal para a variável idade!
// Esta é a zona morta temporal para a variável idade!
// Esta é a zona morta temporal para a variável idade!
// Esta é a zona morta temporal para a variável idade!
let idade = 25; // Pronto, chegamos ao fim da zona morta!
console.log(idade);
}
Como podemos ver acima, se eu acessasse a variável idade
antes de sua declaração, teríamos um ReferenceError
. Isso ocorre por causa da Zona Morta Temporal.
As variáveis com var
, porém, não passam por isso. var
é apenas inicializada por padrão como undefined
, diferentemente das outras declarações.
Qual é a diferença entre declarar e inicializar?
Aqui temos um exemplo de como declarar e de como inicializar uma variável.
function exemploDeEscopo() {
let idade; // 1
idade = 20; // 2
let maos = 2; // 3
}
Declarar uma variável significa reservar para ela um nome na memória no escopo atual. Isso é exemplificado pelo comentário com o número 1.
Inicializar uma variável é definir o valor dessa variável. Isso é exemplificado pelo comentário com o número 2.
Também é possível fazer as duas coisas em uma única linha. Isso é exemplificado pelo comentário com o número 3.
Apenas para reforçar: as variáveis let
e const
existem na Zona Morta Temporal do início do escopo que as envolve até que elas sejam declaradas.
Assim, a partir do treco de código acima, onde está a Zona Morta Temporal para a variável idade
? A variável maos
tem uma Zona Morta Temporal? Se tem, onde é o seu início e o seu final?
Resposta: tanto a variável maos
quanto a variável idade
entram na Zona Morta Temporal. A Zona para maos
termina quando ela é declarada, na mesma linha em que ela é definida como 2. No caso de idade
, a Zona Morta termina quando ela é declarada e quando seu nome é reservado na memória (na etapa 2, onde eu comentei).
Por que a Zona Morta Temporal é criada no local em questão?
Vamos voltar ao nosso primeiro exemplo:
{
// Esta é a zona morta temporal para a variável idade!
// Esta é a zona morta temporal para a variável idade!
// Esta é a zona morta temporal para a variável idade!
// Esta é a zona morta temporal para a variável idade!
let idade = 25; // Pronto, chegamos ao fim da zona morta!
console.log(idade);
}
Se adicionarmos um console.log
dentro da Zona Morta Temporal, veremos este erro:

Por que a zona morta existe entre o início do escopo e a declaração da variável? Qual a razão específica para isso?
Isso tem a ver com o hoisting (em português, algo como "içamento").
A engine do JS que faz a análise do código e o executa tem duas etapas para realizar:
- Analisar o código na Árvore de Sintaxe Abstrata/byte code executável, e
- Execução em tempo de execução (runtime).
O passo 1 é onde ocorre o hoisting. Isso é feito pela engine do JS. Essencialmente, movemos todas as nossas declarações de variáveis para o início do escopo. Aqui temos um exemplo:
console.log(variavelComHoist); // undefined
var variavelComHoist = 1;
Para ser claro, essas variáveis não estão sendo movidas fisicamente dentro do código. O resultado, contudo, seria funcionalmente idêntico ao que vemos abaixo:
var variavelComHoist;
console.log(variavelComHoist); // undefined
contador = 1;
A única diferença entre const
e let
está no fato de que, após o hoisting, seus valores não tem undefined
como padrão.
Apenas para provar que let
e const
também passam pelo hoisting, aqui temos um exemplo:
{
// As duas variáveis abaixo passarão por hoisting na parte superior do seu escopo!
console.log(typeof semSentidoQueNaoExiste); // O resultado é undefined
console.log(typeof nome); // Lança um erro, não é possível acessar 'nome' antes de sua inicialização
let nome = "Kealan";
}
O trecho acima prova que let
passa pelo hoisting acima de onde está declarada, como a engine alerta para isso. Ela sabe que nome
existe (está declarada), mas não podemos acessá-la antes de a inicializarmos.
Se ajudar a se lembrar, pense o seguinte.
Quando as variáveis passam por hoisting, var
é inicializada como undefined
por padrão no processo de hoisting. let
e const
também passam por hoisting, mas não recebe o valor de undefined
quando passa pelo hoisting.
Esse é o único motivo para termos a Zona Morta Temporal. Por isso ela acontece com let
e const
, mas não com var
.
Mais exemplos da Zona Morta Temporal
A Zona Morta Temporal também pode ser criada para parâmetros de função padrão. Algo assim:
function criarZonaMorta(a=b, b) {
}
criarZonaMorta(undefined, 1);
Isso lançará um ReferenceError
, pois a avaliação da variável a
tenta acessar a variável b
antes de ela ser analisada pela engine do JS. Os argumentos da função estão todos dentro da Zona Morta Temporal até serem analisadas.
Mesmo algo simples como let testeDaZona = testeDaZona;
retornaria um erro em função da Zona Morta Temporal. Porém, as variáveis com var
aqui apenas criariam testeDaZona
e a definiriam como undefined
.
Falta apenas um exemplo final e bem mais avançado, de Erik Arvindson (que está envolvido com a evolução e a manutenção das especificações do ECMAScript):
let a = f(); // 1
const b = 2;
function f() { return b; } // 2, b está na Zona Morta Temporal
Você pode seguir os números comentados.
Na primeira linha, chamamos a função f
. Em seguida, tentamos acessar a variável b
(que lança um ReferenceError
, pois b
está na Zona Morta Temporal).
Por que temos a Zona Morta Temporal?
O Dr. Alex Rauschmayer fez um artigo excelente (texto em inglês) sobre o motivo da existência da Zona Morta Temporal. O principal motivo é o fato de ela nos ajudar a capturar erros.
Tentar acessar uma variável antes de ela ser declarada é o jeito errado de se fazer e não deveria ser possível.
Essa também é uma semântica mais esperada e racional para const
(pois const
também passa por hoisting – o que aconteceria se um programador tentasse usar uma variável declarada com const
antes de ela ser declarada em tempo de execução? Que variável deveria estar ali no momento do hoisting?). Foi a melhor abordagem encontrada pela equipe de especificações do ECMAScript.
Como evitar os problemas causados pela Zona Morta Temporal
Colocado de um modo relativamente simples, lembre-se sempre de definir as variáveis declaradas por let
e const
na parte superior do escopo em que se encontram.