Mi a Temporal Dead Zone (TDZ) a JavaScriptben?

Tudom, hogy a Temporal Dead Zone sci-fi kifejezésnek hangzik. De hasznos megérteni, hogy mit jelentenek azok a kifejezések és fogalmak, amelyekkel mindennap dolgozol (vagy meg akarsz ismerkedni).

Csatolja be, mert ez bonyolulttá válik.

Tudja, hogy a JavaScript-ben { }hozzáadhatunk egy hatókörszintet, ahol csak akarjuk?

Tehát mindig a következőket tehettük:

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

Azért vettem fel ezt a részletet, hogy megbizonyosodjak arról, hogy a következő példáknak van-e értelme (mivel nem akartam feltételezni, hogy mindenki ismeri).

Az ES6 előtt nem volt más lehetőség a változók deklarálására, mint a var. De az ES6 hozott minket letés const.

letés a constdeklarációk egyaránt blokk hatókörűek, ami azt jelenti, hogy csak a {}körülöttük érhetők el. varmásrészt nincs megadva ez a korlátozás.

Íme egy példa:

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

A fentiek azért történtek, mert a 2-re történő újbóli deklarálás babyAgecsak a ifblokkon belül érhető el. Ezen túl az elsőt babyAgehasználják. Látja, hogy két különböző változóról van szó?

Ezzel szemben a varnyilatkozatnak nincs blokk hatálya:

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

A végső szembeötlő különbség let/ constés varaz, hogy ha nyilvános varmielőtt az nyilvánították, akkor definiálatlan. De ha ugyanezt teszi a letés miatt const, akkor dobnak egy 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;

A hibát mind a Temporal Dead Zone miatt dobják.

Az Temporal Dead Zone elmagyarázta

Ez az, ami a TDZ: az az állapot leírására, ahol a változók nem érhetők el. Hatókörbe tartoznak, de nincsenek bejelentve.

Az letésconstváltozók a TDZ-ben a körük kezdetétől a deklarálásig léteznek.

Azt is mondhatnánk, hogy a változók a TDZ-ben attól a helytől léteznek, ahová lekötik őket (amikor a változó a belsejében lévő hatókörhöz kötődik), amíg ki nem deklarálják (amikor egy név fenntartva a memóriában ennek a változónak).

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

Láthatja fentebb, hogy ha korábban elérem a kor változót, mint a deklarációja, akkor a ReferenceError. A TDZ miatt.

De varnem fogja megtenni. varcsak alapértelmezés szerint inicializálva van undefineda másik deklarációval ellentétben.

Mi a különbség a deklarálás és az inicializálás között?

Itt van egy példa egy változó deklarálására és egy változó inicializálására.

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

Egy változó deklarálása azt jelenti, hogy a nevet a memóriában fenntartjuk az aktuális hatókörön belül. Ez a megjegyzésekben 1-et jelöl.

Egy változó inicializálása a változó értékének beállítása. Ezt a megjegyzésekben 2-vel jelölik.

Vagy mindig megteheti mindkettőt egy vonalon. Ez a megjegyzésekben 3-al van jelölve.

Csak, hogy ismét megismételjem magam: a letésconstváltozók a TDZ-ben a körük kezdetétől a deklarálásig léteznek.

Tehát a fenti kódrészletből hol a TDZ age? Továbbá handsvan TDZ- je ? Ha igen, hol van a TDZ kezdete és vége a kezek számára?

Ellenőrizze a választ. A kéz és az életkor változók egyaránt belépnek a TDZ-be.

A kezek TDZ-je akkor ér véget, amikor deklarálva van, ugyanaz a vonal 2-re áll.

Az életkorra vonatkozó TZ véget ér, amikor deklarálják, és a név a memóriában van fenntartva (a 2. lépésben, ahol megjegyzést fűztem).

Miért jön létre a TDZ, amikor van?

Térjünk vissza az első példánkra:

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

Ha hozzáadunk egy console.logbelső helyet a TDZ-hez, akkor ezt a hibát látja:

Miért van a TDZ a hatókör teteje és a változó deklaráció között? Mi ennek a konkrét oka?

Az emelés miatt van.

A kódot elemző és végrehajtó JS motornak két lépése van:

  1. A kód elemzése absztrakt szintaxisfába / futtatható bájtkódra, és
  2. Futtatási idő végrehajtása.

Az 1. lépésben történik az emelés, és ezt a JS motor végzi. Lényegében az összes változó deklarációját a hatókörének tetejére helyezi. Tehát egy példa lenne:

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

Az egyértelműség érdekében ezek a változók fizikailag nem mozognak a kódban. De az eredmény funkcionálisan megegyezik az alábbiakkal:

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

Az egyetlen különbség constés letaz, hogy amikor fel vannak emelve, akkor az értékeik nem lesznek alapértelmezettek undefined.

Csak bebizonyításra letés constemelésre, itt van egy példa:

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

A fenti részlet egy bizonyíték, letamely egyértelműen fel van emelve, ahol deklarálták, mivel a motor figyelmeztet bennünket a tényre. Tudja, hogy namelétezik (deklarálva van), de az inicializálás előtt nem férhetünk hozzá.

Ha ez segít emlékezni, gondoljon így.

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.