Što je Temporal Dead Zone (TDZ) u JavaScript-u?

Znam da Temporal Dead Zone zvuči kao znanstveno-fantastična fraza. No, korisno je razumjeti što znače pojmovi i koncepti s kojima svakodnevno radite (ili o kojima želite učiti).

Privežite se jer se to komplicira.

Jeste li svjesni da u JavaScript možemo dodati { }da dodamo razinu opsega gdje god želimo?

Tako smo uvijek mogli učiniti sljedeće:

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

Uključio sam ovaj detalj kako bih bio siguran da nadolazeći primjeri imaju smisla (jer nisam htio pretpostaviti da su to svi znali).

Prije ES6 nije bilo drugog načina za deklariranje varijabli osim var. Ali ES6 nas je doveo leti const.

leti constdeklaracije su blok-opsega, što znači da su dostupne samo unutar {}njih. var, s druge strane, nema ovo ograničenje.

Evo primjera:

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

Gore se dogodilo jer je ponovno deklariranje babyAgena 2 dostupno samo unutar ifbloka. Iza toga koristi se prvi babyAge. Možete li vidjeti da su to dvije različite varijable?

Suprotno tome, vardeklaracija nema opseg bloka:

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

Konačna istaknuta razlika između let/ consti varjest ta što ako pristupite varprije nego što je proglašen, nije definirana. Ali ako učinite isto za leti const, oni bacaju a 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;

Grešku bacaju zbog Privremene mrtve zone.

Objasnio je Temporal Dead Zone

To je ono što je TDZ: pojam koji opisuje stanje u kojem su varijable nedostupne. Opseg su, ali nisu prijavljeni.

The leticonstvarijable postoje u TDZ-u od početka njihovog obuhvaćajućeg opsega do njihove deklaracije.

Također biste mogli reći da varijable postoje u TDZ-u od mjesta na koje se vežu (kada se varijabla veže za opseg u kojem se nalazi) dok se ne deklarira (kada je ime rezervirano u memoriji za tu varijablu).

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

Iznad možete vidjeti da bi, ako pristupim dobnoj varijabli ranije od njene deklaracije, izbacilo ReferenceError. Zbog TDZ-a.

Ali varto neće učiniti. varje samo zadana inicijalizacija za undefinedrazliku od druge deklaracije.

Koja je razlika između prijavljivanja i inicijalizacije?

Evo primjera deklariranja varijable i inicijalizacije varijable.

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

Deklariranje varijable znači da ime rezerviramo u memoriji na trenutnom opsegu. To je u komentarima označeno s 1.

Inicijalizacija varijable je postavljanje vrijednosti varijable. To je u komentarima označeno s 2.

Ili ste uvijek mogli raditi oboje na jednoj liniji. To je u komentarima označeno s 3.

Samo da se opet ponovim: leticonstvarijable postoje u TDZ-u od početka njihovog obuhvaćajućeg opsega do njihove deklaracije.

Dakle, iz gornjeg isječka koda, čemu služi TDZ age? Također, handsima li TDZ? Ako da, gdje je početak i kraj TDZ-a za ruke?

Provjerite svoj odgovor Ruke i dobne varijable ulaze u TDZ.

TDZ za ruke završava kad se proglasi, ista linija koju postavi na 2.

TZ za dob prestaje kad se proglasi i ime se rezervira u memoriji (u koraku 2, gdje sam komentirao).

Zašto se TDZ stvara kad jest?

Vratimo se našem prvom primjeru:

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

Ako dodamo console.logunutrašnjost TDZ-a, vidjet ćete ovu pogrešku:

Zašto TDZ postoji između vrha opsega i deklaracije varijable? Koji je konkretan razlog tome?

To je zbog dizanja.

JS mehanizam koji raščlanjuje i izvršava vaš kôd mora obaviti 2 koraka:

  1. Raščlanjivanje koda u Abstraktno sintaksno stablo / izvršni bajt kôd i
  2. Izvršenje vremena izvođenja.

Korak 1 je mjesto gdje se događa podizanje, a to čini JS motor. U osnovi će premjestiti sve vaše deklaracije varijabli na vrh njihovog opsega. Tako bi primjer bio:

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

Da budemo jasni, ove se varijable fizički ne kreću u kodu. Ali rezultat bi bio funkcionalno identičan dolje navedenom:

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

Jedina razlika između consti letje u tome što kad se podignu, njihove vrijednosti ne postaju zadane undefined.

Dovoljno je dokazati leti consttakođer dizanja, evo primjera:

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

Gornji isječak dokaz je koji letje jasno podignut iznad mjesta na kojem je proglašen, jer nas motor upozorava na činjenicu. Zna da namepostoji (proglašeno je), ali ne možemo mu pristupiti prije nego što se pokrene.

Ako vam pomaže da se sjetite, razmislite o ovome ovako.

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.

It also gives more expected and rational semantics for const (because const is hoisted, what happens if a programmer tries to use it before it is declared at runtime? What variable should it hold at the point when it gets hoisted?), and was the best approach decided by the ECMAScript spec team.

How to avoid the issues the TDZ causes

Relatively simply, always make sure you define your lets and consts at the top of your scope.