Hvad er Temporal Dead Zone (TDZ) i JavaScript?

Jeg ved, at Temporal Dead Zone lyder som en sci-fi-sætning. Men det er nyttigt at forstå, hvad termerne og begreberne du arbejder med hver dag (eller vil lære om) betyder.

Stik ind, fordi dette bliver kompliceret.

Er du opmærksom på, at vi i JavaScript kan tilføje for { }at tilføje et niveau af omfang, hvor vi vil?

Så vi kunne altid gøre nedenstående:

{ { { { { { var madness = true } } } } } }

Jeg har inkluderet denne detalje for at sikre, at de kommende eksempler giver mening (da jeg ikke ville antage, at alle vidste det).

Før ES6 var der ingen anden måde at deklarere andre variabler end var. Men ES6 bragte os letog const.

letog consterklæringer er begge blokomfangede, hvilket betyder, at de kun er tilgængelige inden for {}omgivelserne. varderimod har ikke denne begrænsning.

Her er et eksempel:

let babyAge = 1; let isBirthday = true; if (isBirthday) { let babyAge = 2; } console.log(babyAge); // Hmmmm. This prints 1

Ovenstående er opstået, fordi gendeklarationen babyAgetil to kun er tilgængelig inde i ifblokken. Ud over det babyAgebruges den første . Kan du se, at de er to forskellige variabler?

Derimod har varerklæringen intet blokområde:

var babyAge = 1; var isBirthday = true; if (isBirthday) { var babyAge = 2; } console.log(babyAge); // Ah! This prints 2

Den endelige markante forskel mellem let/ constog varer, at hvis du får adgang, varfør den er erklæret, er den udefineret. Men hvis du gør det samme for letog const, kaster de en 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;

De kaster fejlen alt sammen på grund af Temporal Dead Zone.

Temporal Dead Zone forklaret

Dette er hvad TDZ er: udtrykket til at beskrive den tilstand, hvor variabler ikke kan nås. De er inden for rækkevidde, men de erklæres ikke.

Den letogconstvariabler findes i TDZ fra starten af ​​deres vedlagte omfang, indtil de er erklæret.

Du kan også sige, at variablerne findes i TDZ fra det sted, de bliver bundet (når variablen bliver bundet til det omfang, den er indeni), indtil den erklæres (når et navn er reserveret i hukommelsen til den variabel).

{ // 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); }

Du kan se ovenfor, at hvis jeg åbnede aldersvariablen tidligere end dens erklæring, ville det kaste et ReferenceError. På grund af TDZ.

Men varvil ikke gøre det. varer bare standard initialiseret til i undefinedmodsætning til den anden erklæring.

Hvad er forskellen mellem at erklære og initialisere?

Her er et eksempel på at erklære en variabel og initialisere en variabel.

function scopeExample() { let age; // 1 age = 20; // 2 let hands = 2; // 3 }

At erklære en variabel betyder, at vi reserverer navnet i hukommelsen med det aktuelle omfang. Det er mærket 1 i kommentarerne.

Initialisering af en variabel indstiller værdien af ​​variablen. Det er mærket 2 i kommentarerne.

Eller du kan altid gøre begge dele på en linje. Det er mærket 3 i kommentarerne.

Bare for at gentage mig selv igen: letogconstvariabler findes i TDZ fra starten af ​​deres vedlagte omfang, indtil de er erklæret.

Så fra ovenstående kodestykke, hvor er TDZ til age? Har også handsen TDZ? Hvis ja, hvor er starten og slutningen af ​​TDZ for hænder?

Kontroller dit svar Hænderne og aldersvariablerne kommer begge ind i TDZ.

TDZ for hænder slutter, når den bliver erklæret, den samme linje bliver den sat til 2.

TZ for alder slutter, når den bliver erklæret, og navnet er reserveret i hukommelsen (i trin 2, hvor jeg kommenterede).

Hvorfor oprettes TDZ, når den er?

Lad os gå tilbage til vores første eksempel:

{ // 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); }

Hvis vi tilføjer et console.loginde i TDZ, vil du se denne fejl:

Hvorfor eksisterer TDZ mellem toppen af ​​omfanget og variabeldeklarationen? Hvad er den specifikke grund til det?

Det er på grund af hejsning.

JS-motoren, der parser og udfører din kode, har to trin at gøre:

  1. Parsing af koden i et abstrakt syntaks-træ / eksekverbar bytekode og
  2. Kør tidsudførelse.

Trin 1 er hvor hejsning sker, og dette udføres af JS-motoren. Det vil i det væsentlige flytte alle dine variable erklæringer til toppen af ​​deres anvendelsesområde. Så et eksempel kan være:

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

For at være klar bevæger disse variabler sig ikke fysisk i koden. Men resultatet ville være funktionelt identisk med nedenstående:

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

Den eneste forskel mellem constog leter, at når de hejses, bliver deres værdier ikke misligholdt undefined.

Bare for at bevise letog constogså hejse, her er et eksempel:

{ // 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"; }

Ovenstående uddrag er et bevis, der leter hejst tydeligt over det sted, hvor det blev erklæret, da motoren advarer os om det. Det ved, at der namefindes (det er erklæret), men vi kan ikke få adgang til det, før det initialiseres.

Hvis det hjælper dig med at huske, så tænk på det sådan.

When variables get hoisted, var gets undefined initialized to its value by default in the process of hoisting. let and const also get hoisted, but don't get set to undefined when they get hoisted.

And that's the sole reason we have the TDZ. Which is why it happens with let and const but not var.

More examples of the TDZ

The TDZ can also be created for default function parameters. So something like this:

function createTDZ(a=b, b) { } createTDZ(undefined, 1); 

throws a ReferenceError, because the evaluation of variable a tries to access variable b before it has been parsed by the JS engine. The function arguments are all inside the TDZ until they are parsed.

Even something as simple as let tdzTest = tdzTest; would throw an error due to the TDZ. But var here would just create tdzTest and set it to undefined.

There's one more final and fairly advanced example from Erik Arvindson (who's involved in evolving and maintaining the ECMAScript spec):

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

You can follow the commented numbers.

In the first line we call the f function, and then try to access the b variable (which throws a ReferenceError because b is in the TDZ).

Why do we have the TDZ?

Dr Alex Rauschmayer has an excellent post on why the TDZ exists, and the main reason is this:

It helps us catch errors.

To try and access a variable before it is declared is the wrong way round, and shouldn't be possible.

Det giver også mere forventet og rationel semantik til const(fordi constder hejses, hvad sker der, hvis en programmør prøver at bruge den, før den erklæres ved kørsel? Hvilken variabel skal den have på det tidspunkt, hvor den bliver hejst?), Og var den bedste tilgang besluttet af ECMAScript spec-teamet.

Sådan undgår du de problemer, TDZ forårsager

Relativt enkelt skal du altid sørge for at definere dine lets og consts øverst i dit anvendelsesområde.