Qual é a zona morta temporal?


150

Ouvi dizer que acessar lete constvalores antes de serem inicializados podem causar um ReferenceErrorpor causa de algo chamado zona morta temporal .

O que é a zona morta temporal, como ela se relaciona ao escopo e ao içamento e em que situações é encontrada?


6
possível duplicata de As variáveis ​​declaradas com let ou const não foram içadas no ES6? - embora a questão não incide sobre o TDZ, as respostas são basicamente os mesmos
— Bergi

Respostas:


201

lete consttem duas grandes diferenças entre var:

  1. Eles têm escopo de bloco .
  2. Acessar um varantes de ser declarado tem o resultado undefined; acessar um letou constantes de ser declarado lança ReferenceError:

console.log(aVar); // undefined
console.log(aLet); // causes ReferenceError: aLet is not defined
var aVar = 1;
let aLet = 2;

Parece a partir desses exemplos que as letdeclarações (e const, que funcionam da mesma maneira) não podem ser hasteadas , pois aLetnão parecem existir antes de receber um valor.

Isso não é o caso, no entanto- lete const são içadas (como var, classe function), mas há um período entre uma entrada escopo e ser declarado onde eles não podem ser acessados. Este período é a zona morta temporal (TDZ) .

O TDZ termina quando aLeté declarado , em vez de atribuído :

//console.log(aLet)  // would throw ReferenceError

let aLet;
console.log(aLet); // undefined
aLet = 10;
console.log(aLet); // 10

Este exemplo mostra que leté içado:

let x = 'outer value';
(function() {
  // start TDZ for x
  console.log(x);
  let x = 'inner value'; // declaration ends TDZ for x
}());

Crédito: Zona morta temporal (TDZ) desmistificada

O acesso xno escopo interno ainda causa a ReferenceError. Se letnão fosse içado, seria registrado outer value.

O TDZ é uma coisa boa porque ajuda a destacar erros - acessar um valor antes que ele seja declarado raramente é intencional.

O TDZ também se aplica a argumentos de função padrão. Os argumentos são avaliados da esquerda para a direita e cada argumento está no TDZ até que seja designado:

// b is in TDZ until its value is assigned
function testDefaults(a=b, b) { }
testDefaults(undefined, 1); // throws ReferenceError because the evaluation of a reads b before it has been evaluated.

O TDZ não está ativado por padrão no transpiler babel.js. Ative o modo "alta conformidade" para usá-lo no REPL . Forneça o es6.spec.blockScopingsinalizador para usá-lo com a CLI ou como uma biblioteca.

Leitura adicional recomendada: TDZ desmistificado e ES6 Let, Const e a "Zona morta temporal" (TDZ) em profundidade .



@zeroflagL bom link, obrigado. Também diz: "foo não é declarado, é não inicializado", esse idioma seria útil para esclarecer / corrigir a resposta acima. let fooem um bloco faz com que seja içado e declarado na parte superior desse bloco. A linha de let foocausa que ele seja inicializado. E foo = xyzfaz com que seja atribuído um valor.
— AJP 4/17

2
Acho que este é um ótimo post! No entanto, tive a impressão de que 'let' não estava sujeito a içamento? Encontrei isso nos documentos da Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Não estou tentando ser um cretino, fiquei curioso e estou aberto a esclarecimentos.
— dmarges

1
@jeows A página MDN ainda diz que não foi içada. Você deve tentar editar isso, se estiver realmente certo do que está dizendo. Acho que devo postar uma pergunta sobre isso.
— precisa saber é o seguinte

1
@joews IMO, você pode dizer que eles são içados, mas não podem ser acessados ​​antes que sua declaração seja alcançada por causa do TDZ, ou você pode dizer que eles não são içados, mas o TDZ fará com que qualquer referência a eles gere um erro. Na prática, ambas as afirmações são igualmente verdadeiras. Exceto, eu acho, que você está usando o termo "içar" em um sentido abstrato, como em "içar = sempre que o mecanismo estiver ciente da existência dessa variável". É por isso que? Além disso, o que as especificações dizem sobre isso?
— doubleOrt

7

Içar:
let , const, varestão todos processo içada get.
(o que significa que eles vão para o topo e são declarados no topo do escopo.)

Inicialização:

  • varpassar também pelo processo inicial e obter o valor inicial de undefined.
  • enquanto let, constnão vai jogar o processo inicial, de modo que seus valores ainda são inacessíveis, embora eles já declarados. o que os colocoutemporal dead zone

Então, em breve:

processo de elevação: var, let, const
processo Inicialização: var


0

No caso de variáveis ​​let e const, Basicamente, Zona Mortal Temporal é uma zona

"antes que sua variável seja declarada",

ou seja, onde você não pode acessar o valor dessas variáveis, isso gera um erro.

ex.

let sum = a + 5;        //---------
//some other code       //         | ------>  this is TDZ for variable a
                        //         |
console.log(sum)        //---------
let a = 5;

código acima dá um erro

o mesmo código não dará erro quando usamos var para a variável 'a',

ex.

var sum = a;                            
console.log(sum)     //prints undefined
var a = 5;

o log do console produz "NaN" no segundo exemplo (o resultado da adição undefinede 5). A declaração de var aé içada, o código de inifialização configurado apara 5 não é.
— traktor53

sim, certo, a é içada sem nenhuma inicialização. Portanto, a será indefinido.
— Niranjan harpale

O primeiro exemplo citado não está certo, corrija-o ou remova-o.
— Spidi's Web
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.