Apa itu Zona Mati Temporal (TDZ) di JavaScript?

Saya tahu Temporal Dead Zone terdengar seperti frasa fiksi ilmiah. Tetapi sangat membantu untuk memahami apa arti istilah dan konsep yang Anda kerjakan sehari-hari (atau ingin pelajari).

Ikat, karena ini menjadi rumit.

Tahukah Anda bahwa di JavaScript kita dapat menambahkan { }untuk menambahkan tingkat cakupan di mana pun kita mau?

Jadi kami selalu dapat melakukan hal di bawah ini:

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

Saya telah menyertakan detail ini untuk memastikan bahwa contoh yang akan datang masuk akal (karena saya tidak ingin berasumsi bahwa semua orang mengetahuinya).

Sebelum ES6 tidak ada cara lain untuk mendeklarasikan variabel selain var. Tapi ES6 membawa kami letdan const.

letdan constdeklarasi memiliki cakupan blok, yang berarti deklarasi hanya dapat diakses di {}sekitarnya. var, di sisi lain, tidak memiliki batasan ini.

Berikut contohnya:

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

Hal di atas terjadi karena deklarasi ulang babyAgeke 2 hanya tersedia di dalam ifblok. Di luar itu, yang pertama babyAgedigunakan. Dapatkah Anda melihat bahwa mereka adalah dua variabel yang berbeda?

Sebaliknya, vardeklarasi tidak memiliki cakupan blok:

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

Perbedaan penting terakhir antara let/ constdan varadalah jika Anda mengakses varsebelum dideklarasikan, itu tidak ditentukan. Tetapi jika Anda melakukan hal yang sama untuk letdan const, mereka melempar 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;

Mereka membuang kesalahan semua karena Zona Mati Temporal.

Zona Mati Temporal menjelaskan

Inilah yang dimaksud dengan TDZ: istilah untuk menggambarkan keadaan di mana variabel tidak dapat dijangkau. Mereka berada dalam cakupan, tetapi tidak dideklarasikan.

The letdanconstvariabel ada di TDZ dari awal cakupan penutupnya hingga dideklarasikan.

Anda juga bisa mengatakan bahwa variabel ada di TDZ dari tempat mereka terikat (ketika variabel terikat ke ruang lingkup di dalamnya) sampai dideklarasikan (ketika nama dicadangkan dalam memori untuk variabel itu).

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

Anda dapat melihat di atas bahwa jika saya mengakses variabel usia lebih awal dari deklarasinya, itu akan melempar ReferenceError. Karena TDZ.

Tapi vartidak akan melakukan itu. varsecara default diinisialisasi undefinedtidak seperti deklarasi lainnya.

Apa perbedaan antara mendeklarasikan dan menginisialisasi?

Berikut adalah contoh mendeklarasikan variabel dan menginisialisasi variabel.

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

Mendeklarasikan variabel berarti kita menyimpan nama dalam memori pada lingkup saat ini. Itu diberi label 1 di komentar.

Menginisialisasi variabel adalah mengatur nilai variabel. Itu diberi label 2 di komentar.

Atau Anda selalu dapat melakukan keduanya dalam satu baris. Itu diberi label 3 di komentar.

Hanya untuk mengulangi diri saya lagi: letdanconstvariabel ada di TDZ dari awal cakupan penutupnya hingga dideklarasikan.

Jadi dari potongan kode di atas, untuk apa TDZ itu age? Juga, apakah handspunya TDZ? Jika ya, di mana awal dan akhir TDZ untuk tangan?

Periksa jawaban Anda Kedua tangan dan variabel usia memasukkan TDZ.

TDZ untuk tangan berakhir saat dideklarasikan, baris yang sama disetel ke 2.

TZ untuk usia berakhir saat dideklarasikan, dan namanya disimpan dalam memori (di langkah 2, di mana saya berkomentar).

Mengapa TDZ dibuat saat itu?

Mari kembali ke contoh pertama kita:

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

Jika kami menambahkan console.logdi dalam TDZ, Anda akan melihat kesalahan ini:

Mengapa TDZ ada di antara bagian atas cakupan dan deklarasi variabel? Apa alasan spesifiknya?

Itu karena mengangkat.

Mesin JS yang mengurai dan menjalankan kode Anda memiliki 2 langkah yang harus dilakukan:

  1. Parsing kode menjadi Pohon Sintaks Abstrak / kode byte yang dapat dieksekusi, dan
  2. Jalankan eksekusi waktu.

Langkah 1 adalah tempat pengangkatan terjadi, dan ini dilakukan oleh mesin JS. Ini pada dasarnya akan memindahkan semua deklarasi variabel Anda ke atas ruang lingkupnya. Jadi contohnya adalah:

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

Untuk memperjelas, variabel ini tidak secara fisik bergerak dalam kode. Namun, hasilnya secara fungsional identik dengan di bawah ini:

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

Satu-satunya perbedaan antara constdan letadalah bahwa ketika mereka diangkat, nilainya tidak menjadi default undefined.

Sekadar membuktikan letdan constjuga hoist, berikut contohnya:

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

Potongan di atas adalah bukti yang letdengan jelas diangkat di atas tempat itu dinyatakan, saat mesin memberi tahu kita tentang fakta tersebut. Itu tahu nameada (itu dideklarasikan), tetapi kita tidak dapat mengaksesnya sebelum diinisialisasi.

Jika itu membantu Anda untuk mengingat, pikirkanlah seperti ini.

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.