Rumah > Artikel > hujung hadapan web > JS — Memahami Persekitaran Leksikal dalam JavaScript — Deep Dive — Bahagian 1
Sebagai pembangun, saya sering menemui istilah "persekitaran leksikal" tetapi saya tidak pernah benar-benar meluangkan masa untuk menerokainya secara mendalam. Jadi, saya memutuskan untuk menyelam lebih dalam dan mendokumenkan penemuan saya dalam siaran ini - kerana "berkongsi adalah penyayang ;)". Menjelang akhir siaran ini, saya berharap kita berdua akan mempunyai pemahaman yang kukuh tentang apa itu persekitaran leksikal dan kita juga akan meneroka perkara yang berlaku dalam ingatan, apakah struktur data dan cara tindanan panggilan berfungsi. Jangan risau - Saya akan pastikan ia ringkas dan jelas!
Sebelum menyelami butirannya, izinkan saya mulakan dengan gambaran ringkas. Jangan risau jika sesetengah konsep kelihatan rumit pada mulanya - saya akan memecahkannya dan menggunakan analogi untuk menjadikannya lebih mudah difahami.
Persekitaran leksikal ialah struktur data khas dalam JavaScript yang menjejak skop pembolehubah dan fungsi pada titik tertentu dalam kod.
Struktur data ialah cara untuk menyusun dan menyimpan maklumat dalam komputer supaya ia boleh digunakan dengan cekap. Contoh biasa termasuk tatasusunan, objek, senarai dan pepohon. Lihat lagi: Tutorial Struktur Data - GeeksforGeeks
Istilah "leksikal" bermaksud bahawa skop dan kebolehcapaian pembolehubah dan fungsi ditentukan oleh tempat ia ditulis dalam kod, bukannya cara atur cara berjalan.
Peranan utama persekitaran leksikal:
Berikut ialah contoh kod ringkas yang mengandungi tiga persekitaran leksikal yang berbeza:
var sheep = 1; // Global sheep function drinkWater() { let waterTemperature = "cold"; console.log("The sheep is drinking " + waterTemperature + " water."); } var sheepHouseInArea = true; // Indicates whether the sheep house is present if (sheepHouseInArea) { let lambs = 2; // Lambs inside the house console.log("There are " + sheep + " sheep in the total area and " + lambs + " lambs!"); } // This will result in an error because 'lambs' // is only accessible inside the if block! console.log("How many lambs are there? " + lambs);
Tiga persekitaran leksikal dalam kod ini ialah: skop global, skop fungsi drinkWater dan skop blok if. Untuk menjadikan konsep ini lebih mudah difahami, mari kita gunakan analogi mudah yang melibatkan biri-biri:
Semasa berjalan di luar minggu ini, saya terjumpa beberapa ekor biri-biri di dalam kawasan berpagar dan berfikir, "Hei, ini seperti persekitaran leksikal!"
Biar saya terangkan: Bayangkan kawasan berpagar dengan kambing biri-biri di dalamnya. Kambing biri-biri hanya boleh melakukan perkara di dalam pagar, seperti makan rumput. Sekarang, bayangkan terdapat sebuah rumah biri-biri kecil di dalam pagar di mana kambing boleh tinggal. Kambing di dalam rumah tidak boleh keluar, tetapi kambing di luar boleh masuk.
Pagar mewakili keseluruhan kawasan di mana segala-galanya wujud - biri-biri, kambing biri-biri, rumah dan rumput. Kawasan berpagar inilah yang kami sebut sebagai skop global. Di dalam kawasan berpagar ini, rumah biri-biri adalah bahagian yang lebih kecil dan berasingan, mewakili skop blok. Akhirnya, rumput yang dimakan oleh biri-biri (yumyum) adalah seperti fungsi dalam skop global, aktiviti atau tindakan tertentu yang boleh dilakukan oleh biri-biri dalam ruang tersebut.
Dalam blok kod, skop global diwakili oleh kotak merah, skop fungsi drinkWater oleh kotak biru, dan skop blok if oleh kotak hijau. Ini ialah tiga persekitaran leksikal.
Kambing biri-biri (diwakili oleh biri-biri var = 1;) melambangkan pembolehubah dalam skop global, bebas berkeliaran di kawasan berpagar. Ia boleh digunakan di luar dan di dalam fungsi drinkWater dan blok if.
Fungsi drinkWater mewakili tindakan yang boleh dilakukan oleh biri-biri di dalam kawasan berpagar. Kita boleh memanggil fungsi drinkWater dari mana-mana sahaja dalam skop global. Walau bagaimanapun, fungsi itu sendiri mencipta persekitaran leksikal baharu apabila ia ditakrifkan. Di dalam fungsi ini, pembolehubah (seperti biarkan airTemperature = 'sejuk';) hanya boleh diakses dalam fungsi.
Blok if mencipta skop baharu yang lebih kecil. Dalam skop ini, diwakili oleh rumah biri-biri, terdapat 2 ekor kambing (biar kambing = 2). Di dalam skop ini, pernyataan console.log mencatatkan nilai pembolehubah domba serta pembolehubah biri-biri global. Pembolehubah domba adalah khusus untuk skop blok, manakala pembolehubah biri-biri diambil daripada persekitaran induk (skop global). Ini dimungkinkan oleh Rujukan Persekitaran Luar, yang membenarkan JavaScript mencari rantai skop dan menyelesaikan pembolehubah yang tidak ditemui dalam persekitaran semasa.
Rujukan Persekitaran Luar ialah rujukan atau penunjuk dalam persekitaran leksikal. Ia menunjuk kepada persekitaran leksikal induk, membenarkan JavaScript menyelesaikan pembolehubah yang tidak ditemui dalam persekitaran semasa dengan mencari rantai skop.
Bolehkah anda mengubah suai fungsi drinkWater() supaya ia mencatatkan jumlah bilangan biri-biri yang ditakrifkan dalam skop global yang boleh meminum air? Kongsikan jawapan anda di ruangan komen!
Jadi, kami melihat bahawa terdapat tiga persekitaran leksikal dalam kod ini: skop global, skop fungsi dan skop blok. Apabila terdapat lebih daripada satu persekitaran leksikal, kami memanggilnya pelbagai persekitaran leksikal. Adalah penting untuk memahami bahawa pelbagai persekitaran leksikal boleh wujud dalam satu kod. Setiap kali skop baharu dicipta (cth., fungsi atau blok), persekitaran leksikal baharu dijana, bermakna bahagian kod anda yang berlainan boleh mempunyai persekitaran berasingan mereka sendiri.
Sekarang kita memahami cara persekitaran leksikal berfungsi, mari kita selami dengan lebih mendalam konsep rekod persekitaran.
Apabila persekitaran leksikal dicipta - sama ada untuk skop global, fungsi atau blok - JavaScript secara automatik menjana rekod persekitaran untuknya.
Rekod persekitaran ini ialah struktur data yang menjejaki semua pembolehubah, fungsi dan pengikatan lain yang boleh diakses dalam skop khusus tersebut. Pada asasnya, ia bertindak sebagai storan dalaman untuk semua yang ditakrifkan dalam persekitaran itu, memastikan data yang betul tersedia apabila diperlukan semasa pelaksanaan kod.
Perbezaan utama antara persekitaran leksikal dan rekod persekitaran:
Persekitaran leksikal ialah tempat kod JavaScript dijalankan. Anggap ia sebagai "tetapan" atau "konteks" di mana kod anda wujud. Konteks ini termasuk skop pembolehubah dan fungsi, menentukan yang mana tersedia atau boleh diakses pada mana-mana titik dalam kod. Sebagai contoh, dalam kod kami, pembolehubah domba hanya boleh diakses dalam persekitaran sempadan hijau (skop blok). Persekitaran leksikal juga termasuk Rujukan Persekitaran Luar (yang telah kami terangkan), membenarkan akses kepada pembolehubah dalam persekitaran induk.
Rekod persekitaran ialah kawasan storan khusus dalam persekitaran leksikal yang menyimpan pembolehubah sebenar, pengisytiharan fungsi dan pengecam lain yang digunakan dalam persekitaran itu. Walaupun persekitaran leksikal ialah konteks yang lebih luas, rekod persekitaran ialah tempat data kod - seperti nilai pembolehubah dan definisi fungsi - disimpan. Setiap kali JavaScript perlu mengakses pembolehubah atau fungsi, ia kelihatan dalam rekod persekitaran persekitaran leksikal semasa.
Mari kita terangkan semula persekitaran leksikal dan rekod persekitaran menggunakan contoh kod kami:
Terdapat tiga persekitaran leksikal, setiap satu dengan rekod persekitarannya sendiri:
Pengisytiharan ini boleh diakses sepanjang keseluruhan kod. Persekitaran global juga merujuk kepada fungsi drinkWater, yang ditakrifkan dalam persekitaran ini, dan pernyataan if, yang membawa kepada penciptaan skop bloknya sendiri apabila dilaksanakan.
Skop Fungsi (minumAir, kotak biru), Persekitaran Leksikal 2:
Rekod persekitaran dalam persekitaran ini mengandungi suhu air berubah-ubah, yang diisytiharkan menggunakan biarkan di dalam fungsi drinkWater. Pembolehubah ini hanya boleh diakses dalam fungsi. Walau bagaimanapun, fungsi ini juga boleh mengakses pembolehubah dalam persekitaran global seperti biri-biri.
Skop Sekatan (jika blok, kotak hijau), Persekitaran Leksikal 3:
Rekod persekitaran dalam persekitaran ini mengandungi kambing yang berubah-ubah, diisytiharkan menggunakan let di dalam blok if. Pembolehubah ini hanya boleh diakses dalam skop blok khusus ini. Blok itu juga boleh mengakses pembolehubah daripada persekitaran induknya, seperti biri-biri dan sheepHouseInArea.
Selepas menyelam jauh ke dalam persekitaran leksikal dan rekod persekitaran, kami kini bersedia untuk memahami cara JavaScript mengurus memori dan akses berubah semasa pelaksanaan kod.
Apabila kod anda dijalankan, JavaScript mencipta persekitaran leksikal baharu untuk setiap fungsi atau blok kod. Setiap persekitaran mempunyai rekod persekitarannya sendiri, menyimpan semua pembolehubah dan fungsi yang ditakrifkan dalam skop tersebut. Persediaan ini memastikan penggunaan memori yang cekap, seperti yang telah kita bincangkan.
Behind the scenes, the JavaScript engine handles these lexical environments in memory. The call stack is used for tracking function calls, while block scopes create new lexical environments linked to their outer environments. However, unlike functions, these block scopes aren't pushed onto the call stack.
The call stack is a fundamental concept in how Javascript executes code.
The call stack is a data structure that keeps track of function calls in a program. It works on a Last-In-First-Out (LIFO) principle. Here's how it works:
Key points about the call stack:
Now you know why its called stack overflow haha!
Here's a simple example to illustrate:
function greet(name) { console.log('Hello, ' + name); } function processUser(user) { greet(user); } processUser('Alice');
As each function completes, it's popped off the stack until we return to the global context.
In our sheep code example, can you identify if anything is placed on the call stack during execution? Share your thoughts in the comments section!
That's it for Part 1! I hope this post has helped you gain a solid understanding of how JavaScript handles lexical environments, environment records, and what happens behind the scenes in memory. I've learned a lot in the process, and I hope you have too. If you have any questions or feedback, I'd love to hear from you - let's learn and improve together!
I titled this post 'Part 1' because I plan to follow up with 'Part 2,' where I'll dive into three major concepts that are closely linked to lexical environments:
These concepts are super important because they directly impact how your JavaScript code behaves. Understanding them will help you write cleaner, more efficient code and avoid some common pitfalls.
Stay tuned!
--
Please also follow me on my Medium: https://medium.com/@ensing89
Atas ialah kandungan terperinci JS — Memahami Persekitaran Leksikal dalam JavaScript — Deep Dive — Bahagian 1. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!