Quelle est la zone morte temporelle?

150

J'ai entendu dire que l'accès letet les constvaleurs avant leur initialisation peuvent provoquer une ReferenceErrorcause de quelque chose appelé la zone morte temporelle .

Qu'est-ce que la zone morte temporelle, comment se rapporte-t-elle à la portée et au levage, et dans quelles situations est-elle rencontrée?

joews
la source
6
duplication possible de Les variables déclarées avec let ou const ne sont-elles pas levées dans ES6? - bien que la question ne se concentre pas sur le TDZ, les réponses sont fondamentalement les mêmes
Bergi

Réponses:

201

letet constont deux grandes différences de var:

  1. Ils ont une portée de bloc .
  2. L'accès à a varavant qu'il ne soit déclaré a le résultat undefined; accéder à un letou constavant qu'il ne soit déclaré lance ReferenceError:

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

Il ressort de ces exemples que les letdéclarations (et const, qui fonctionne de la même manière) ne peuvent pas être hissées , car aLetne semble pas exister avant qu'on lui attribue une valeur.

Ce n'est pas le cas, cependant - letet const sont hissés (comme var, classet function), mais il y a une période entre l'entrée dans le champ d'application et la déclaration où ils ne sont pas accessibles. Cette période est la zone morte temporelle (TDZ) .

Le TDZ se termine quand aLetest déclarée , plutôt que attribué :

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

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

Cet exemple montre qu'il letest hissé:

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

Crédit: Temporal Dead Zone (TDZ) démystifié

L'accès xdans la portée interne provoque toujours un ReferenceError. S'il letn'était pas hissé, il se connecterait outer value.

Le TDZ est une bonne chose car il permet de mettre en évidence les bogues - accéder à une valeur avant qu'elle n'ait été déclarée est rarement intentionnel.

Le TDZ s'applique également aux arguments de fonction par défaut. Les arguments sont évalués de gauche à droite, et chaque argument est dans la TDZ jusqu'à ce qu'il soit affecté:

// 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.

Le TDZ n'est pas activé par défaut dans le transpilateur babel.js . Activez le mode «haute conformité» pour l'utiliser dans le REPL . Fournissez l' es6.spec.blockScopingindicateur pour l'utiliser avec l'interface de ligne de commande ou comme bibliothèque.

Lectures complémentaires recommandées: TDZ démystifié et ES6 Let, Const et la «zone morte temporelle» (TDZ) en profondeur .

joews
la source
3
Aussi intéressant: Pourquoi y a-t-il une zone morte temporelle
un meilleur oliver
@zeroflagL bon lien, merci. Il dit aussi: "foo n'est pas non déclaré, il n'est pas initialisé", ce langage serait utile pour clarifier / corriger dans la réponse ci-dessus. let foodans un bloc fait qu'il soit hissé et déclaré en haut de ce bloc. La ligne de let fooprovoque son initialisation. Et foo = xyzlui attribue une valeur.
AJP
2
Je pense que c'est un super article! Cependant, j'avais l'impression que «let» n'était pas sujet au levage? J'ai trouvé cela dans la documentation de Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ... Je n'essaye pas d'être un curmudgeon, j'étais juste curieux et je suis ouvert à la clarification.
dmarges
1
@jeows La page MDN dit toujours qu'ils ne sont pas hissés. Vous devriez essayer de modifier cela, si vous êtes vraiment sûr de ce que vous dites. Je pense que je devrais poster une question à ce sujet.
doubleOrt
1
@joews IMO, vous pouvez soit dire qu'ils sont levés mais qu'ils ne sont pas accessibles avant que leur déclaration ne soit atteinte à cause du TDZ, soit vous pouvez dire qu'ils ne sont pas levés mais que le TDZ provoquera une erreur. En pratique, les deux affirmations sont également vraies. Sauf que, je pense, vous utilisez le terme «levage» dans un sens abstrait, comme dans «levage = chaque fois que le moteur est conscient de l'existence de cette variable». Ç'est pourquoi ? De plus, que disent les spécifications à ce sujet?
doubleOrt
7

Hissage:
let , const, varsont tous Tracez votre processus hissés.
(ce qui veut dire qu'ils vont plus haut et déclarent en haut de la portée.)

Initialisation:

  • varpassez également par le processus initial et obtenez la valeur initiale de undefined.
  • tandis que let, constne sont pas allés lancer le processus initial, de sorte que leurs valeurs sont toujours inaccessibles, bien qu'elles aient déjà été déclarées. dans quoi les mettretemporal dead zone

Donc en bref:

Procédé de levage: var, let, const
Processus d' initialisation: var

ofir_aghai
la source
0

En cas de variables let et const, Fondamentalement, la zone morte temporelle est une zone

"avant que votre variable ne soit déclarée",

c'est à dire là où vous ne pouvez pas accéder à la valeur de ces variables, cela lancera une erreur.

ex.

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

le code ci-dessus donne une erreur

le même code ne donnera pas d'erreur lorsque nous utilisons var pour la variable 'a',

ex.

var sum = a;                            
console.log(sum)     //prints undefined
var a = 5;
niranjan harpale
la source
le journal de la console produit "NaN" dans le deuxième exemple (le résultat de l'ajout undefinedet 5). La déclaration de var aest hissée, le code d'inifialisation mis aà 5 ne l'est pas.
traktor53
oui, c'est vrai, a est hissé sans aucune initialisation. Donc, un sera indéfini.
niranjan harpale
Le 1er exemple cité n'est pas correct, veuillez le corriger ou le supprimer.
Spidi's Web