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.