O que é a zona morta temporal (TDZ) em JavaScript?

O que é a zona morta temporal (TDZ) em JavaScript?

6 de October, 2020 0 By António César de Andrade


Eu sei que a Zona Morta Temporal soa como uma frase de ficção científica. Mas é útil entender o que significam os termos e conceitos com os quais você trabalha diariamente (ou sobre os quais deseja aprender).

Coloque o cinto, porque isso fica complicado.

Você está ciente de que em JavaScript podemos adicionar { } adicionar um nível de escopo onde quisermos?

Portanto, podemos sempre fazer o seguinte:

{ { { { { { var madness = true } } } } } }
Felizmente, você não vê isso no código de produção!

Incluí esse detalhe para garantir que os próximos exemplos façam sentido (já que não queria presumir que todos soubessem).

Antes do ES6, não havia outra maneira de declarar variáveis ​​além var. Mas ES6 nos trouxe let e const.

let e const declarações têm escopo de bloco, o que significa que só podem ser acessadas dentro do { } cercando-os. var, por outro lado, não tem essa restrição.

Aqui está um exemplo:

let babyAge = 1;
let isBirthday = true;

if (isBirthday) {
	let babyAge = 2; 
}

console.log(babyAge); // Hmmmm. This prints 1
Duas variáveis ​​únicas, com valores diferentes.

O anterior ocorreu porque a nova declaração de babyAge a 2 está disponível apenas dentro do if quadra. Além disso, o primeiro babyAge é usado. Você pode ver que são duas variáveis ​​diferentes?

Em contraste, o var declaração não tem escopo de bloco:

var babyAge = 1;
var isBirthday = true;

if (isBirthday) {
	var babyAge = 2; 
}

console.log(babyAge); // Ah! This prints 2
Uma variável com seu valor declarado novamente.

A diferença saliente final entre let / const e var é isso se você acessar var antes de ser declarado, ele é indefinido. Mas se você fizer o mesmo por let e const, eles jogam um ReferenceError.

console.log(varNumber); // undefined
console.log(letNumber); // Doesn't log, as it throws a ReferenceError letNumber is not defined

var varNumber = 1;
let letNumber = 1;

Eles lançam o erro tudo por causa da Zona Morta Temporal.

Explicação da Zona Morta Temporal

Isso é o que o TDZ é: o termo para descrever o estado em que as variáveis ​​são inacessíveis. Eles estão no escopo, mas não são declarados.

o let e const as variáveis ​​existem no TDZ desde o início de seu escopo interno até que sejam declaradas.

Você também poderia dizer que as variáveis ​​existem no TDZ desde o lugar em que foram vinculadas (quando a variável é vinculada ao escopo em que está) até que seja declarada (quando um nome é reservado na memória para essa variável).

{
 	// This is the temporal dead zone for the age variable!
	// This is the temporal dead zone for the age variable!
	// This is the temporal dead zone for the age variable!
 	// This is the temporal dead zone for the age variable!
	let age = 25; // Whew, we got there! No more TDZ
	console.log(age);
}
A zona morta temporal capturada e catalogada.

Você pode ver acima que se eu acessasse a variável de idade antes de sua declaração, ele geraria um ReferenceError. Por causa do TDZ.

Mas var não vai fazer isso. var é apenas inicializado por padrão para undefined ao contrário da outra declaração.

Qual é a diferença entre declarar e inicializar?

Aqui está um exemplo de declaração de uma variável e inicialização de uma variável.

function scopeExample() {

    let age; // 1
    age = 20; // 2
    let hands = 2; // 3
}
Declarando vs inicializando uma variável.

Declarar uma variável significa que reservamos o nome na memória no escopo atual. Isso é marcado como 1 nos comentários.

Inicializar uma variável é definir o valor da variável. Isso é marcado como 2 nos comentários.

Ou você sempre pode fazer ambos em uma linha. Isso é rotulado como 3 nos comentários.

Só para me repetir: o let e const as variáveis ​​existem no TDZ desde o início de seu escopo interno até que sejam declaradas.

Portanto, a partir do trecho de código acima, onde está o TDZ para age? Além disso, hands tem um TDZ? Em caso afirmativo, onde é o início e o fim do TDZ para as mãos?

Verifique sua resposta

As variáveis ​​mãos e idade entram no TDZ.

O TDZ para mãos termina quando é declarado, a mesma linha que é definida como 2.

O TZ para idade termina quando é declarado, e o nome é reservado na memória (na etapa 2, onde comentei).

Por que o TDZ é criado quando é?

Vamos voltar ao nosso primeiro exemplo:

{
    // This is the temporal dead zone for the age variable!
    // This is the temporal dead zone for the age variable!
    // This is the temporal dead zone for the age variable!
    // This is the temporal dead zone for the age variable!
    let age = 25; // Whew, we got there! No more TDZ
    console.log(age);
}

Se adicionarmos um console.log dentro do TDZ você verá este erro:

Por que o TDZ existe entre o topo do escopo e a declaração da variável? Qual é a razão específica para isso?

É por causa do içamento.

O mecanismo JS que analisa e executa seu código tem 2 etapas a seguir:

  1. Análise do código em uma árvore de sintaxe abstrata / código de byte executável e
  2. Execução em tempo de execução.

A etapa 1 é onde o içamento acontece, e isso é feito pelo mecanismo JS. Basicamente, ele moverá todas as suas declarações de variáveis ​​para o topo de seu escopo. Portanto, um exemplo seria:

console.log(hoistedVariable); // undefined
var hoistedVariable = 1;

Para ser claro, essas variáveis ​​não estão se movendo fisicamente no código. Mas, o resultado seria funcionalmente idêntico ao abaixo:

var hoistedVariable;

console.log(hoistedVariable); // undefined
counter = 1;

A única diferença entre const e let é que quando eles são içados, seus valores não são padronizados para undefined.

Só para provar let e const também içar, aqui está um exemplo:

{
    // Both the below variables will be hoisted to the top of their scope!
	console.log(typeof nonsenseThatDoesntExist); // Prints undefined
	console.log(typeof name); // Throws an error, cannot access 'name' before initialization

	let name = "Kealan";
}

O snippet acima é a prova de que let está claramente içado acima de onde foi declarado, pois o motor nos alerta para o fato. Sabe name existe (é declarado), mas não podemos acessá-lo antes de ser inicializado.

Se ajudar você a se lembrar, pense assim.

Quando as variáveis ​​são levantadas, var pega undefined inicializado com seu valor por padrão no processo de içamento. let e const também são içados, mas não configurados para undefined quando eles são içados.

E essa é a única razão pela qual temos o TDZ. É por isso que acontece com let e const mas não var.

Mais exemplos do TDZ

O TDZ também pode ser criado para parâmetros de função padrão. Então, algo assim:

function createTDZ(a=b, b) {
}

createTDZ(undefined, 1); 

joga um ReferenceError, porque a avaliação da variável a tenta acessar a variável b antes de ser analisado pelo mecanismo JS. Os argumentos da função estão todos dentro do TDZ até que sejam analisados.

Mesmo algo tão simples como let tdzTest = tdzTest; lançaria um erro devido ao TDZ. Mas var aqui seria apenas criar tdzTest e configurá-lo para undefined.

Há mais uma final e exemplo bastante avançado de Erik Arvindson (que está envolvido na evolução e manutenção da especificação ECMAScript):

let a = f(); // 1
const b = 2;
function f() { return b; } // 2, b is in the TDZ
Um exemplo final de TDZ.

Você pode seguir os números comentados.

Na primeira linha chamamos de f função e, em seguida, tente acessar o b variável (que lança um ReferenceError Porque b está no TDZ).

Por que temos o TDZ?

Dr. Alex Rauschmayer tem um excelente postar em porque o TDZ existe, e o principal motivo é este:

Isso nos ajuda a detectar erros.

Tentar acessar uma variável antes de ser declarada é o caminho errado e não deveria ser possível.

Ele também fornece uma semântica mais esperada e racional para const (Porque const é içado, o que acontece se um programador tentar usá-lo antes de ser declarado em tempo de execução? Qual variável deve ser mantida no ponto em que é içada?), E foi a melhor abordagem decidida pela equipe de especificações ECMAScript.

Como evitar os problemas que o TDZ causa

De forma relativamente simples, sempre certifique-se de definir seu letareia consts no topo de seu escopo.

Você pode ler mais sobre este tópico nas seguintes postagens:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone

https://exploringjs.com/es6/ch_variables.html#sec_temporal-dead-zone

https://ponyfoo.com/articles/es6-let-const-and-temporal-dead-zone-in-depth



Fonte

Click to rate this post!
[Total: 0 Average: 0]