JavaScript adalah bahasa yang sangat berorientasi pada fungsi. Ini memberi kita banyak kebebasan. Suatu fungsi dapat dibuat kapan saja, diteruskan sebagai argumen ke fungsi lain, dan kemudian dipanggil dari tempat kode yang sama sekali berbeda nanti Show Kita sudah tahu bahwa suatu fungsi dapat mengakses variabel di luarnya (variabel "luar") Tetapi apa yang terjadi jika variabel luar berubah sejak suatu fungsi dibuat? Dan bagaimana jika suatu fungsi diteruskan sebagai argumen dan dipanggil dari tempat kode lain, apakah ia akan mendapatkan akses ke variabel luar di tempat baru? Mari perluas pengetahuan kita untuk memahami skenario ini dan yang lebih kompleks Kami akan berbicara tentang Dalam JavaScript, ada 3 cara untuk mendeklarasikan variabel. 4, 5 (yang modern), dan 6 (sisa masa lalu)
Jika sebuah variabel dideklarasikan di dalam blok kode 1, itu hanya terlihat di dalam blok ituSebagai contoh _Kita dapat menggunakan ini untuk mengisolasi sepotong kode yang melakukan tugasnya sendiri, dengan variabel yang hanya menjadi miliknya
Akan ada kesalahan tanpa blok Perlu diketahui, tanpa blok terpisah akan terjadi kesalahan, jika kita menggunakan 4 dengan nama variabel yang ada _Untuk _3, 4, 5 dan seterusnya, variabel yang dideklarasikan dalam 1 juga hanya terlihat di dalam
Di sini, setelah 3 selesai, 8 di bawah tidak akan melihat 9, maka kesalahanItu bagus, karena memungkinkan kita membuat variabel blok-lokal, khusus untuk cabang 3Hal serupa berlaku untuk _4 dan 5 loop
Secara visual, _3 berada di luar 1. Tapi konstruksi _4 spesial di sini. variabel, yang dideklarasikan di dalamnya, dianggap sebagai bagian dari blokSuatu fungsi disebut "bersarang" ketika dibuat di dalam fungsi lain Sangat mudah untuk melakukan ini dengan JavaScript Kita dapat menggunakannya untuk mengatur kode kita, seperti ini
Di sini fungsi bersarang _6 dibuat untuk kenyamanan. Itu dapat mengakses variabel luar dan dapat mengembalikan nama lengkap. Fungsi bersarang cukup umum dalam JavaScriptYang jauh lebih menarik, fungsi bersarang dapat dikembalikan. baik sebagai properti objek baru atau sebagai hasil dengan sendirinya. Ini kemudian dapat digunakan di tempat lain. Di mana pun, ia masih memiliki akses ke variabel luar yang sama Di bawah, _7 membuat fungsi "penghitung" yang mengembalikan angka berikutnya pada setiap pemanggilan
Meskipun sederhana, varian kode yang sedikit dimodifikasi memiliki kegunaan praktis, misalnya, sebagai penghasil angka acak untuk menghasilkan nilai acak untuk pengujian otomatis Bagaimana cara kerjanya? Memahami hal-hal seperti itu bagus untuk keseluruhan pengetahuan JavaScript dan bermanfaat untuk skenario yang lebih kompleks. Jadi mari kita sedikit lebih dalam Di sini jadilah naga Penjelasan teknis mendalam ada di depan Sejauh saya ingin menghindari detail bahasa tingkat rendah, pemahaman apa pun tanpanya akan kurang dan tidak lengkap, jadi bersiaplah Untuk kejelasan, penjelasannya dibagi menjadi beberapa langkah Dalam JavaScript, setiap fungsi yang berjalan, blok kode 1, dan skrip secara keseluruhan memiliki objek terkait internal (tersembunyi) yang dikenal sebagai Lingkungan LexicalObjek Lexical Environment terdiri dari dua bagian
"Variabel" hanyalah properti dari objek internal khusus, 0. "Untuk mendapatkan atau mengubah variabel" berarti "mendapatkan atau mengubah properti dari objek itu"Dalam kode sederhana tanpa fungsi ini, hanya ada satu Lingkungan Lexical Inilah yang disebut Lingkungan Leksikal global, yang terkait dengan keseluruhan skrip Pada gambar di atas, persegi panjang berarti Rekam Lingkungan (penyimpanan variabel) dan tanda panah berarti referensi luar. Lingkungan Leksikal global tidak memiliki referensi luar, itu sebabnya panah menunjuk ke 1Saat kode mulai dijalankan dan berlanjut, Lingkungan Lexical berubah Ini kode yang sedikit lebih panjang Persegi panjang di sisi kanan menunjukkan bagaimana Lingkungan Leksikal global berubah selama eksekusi
Semuanya terlihat sederhana untuk saat ini, bukan?
Leksikal Lingkungan adalah objek spesifikasi "Lexical Environment" adalah objek spesifikasi. itu hanya ada "secara teoritis" untuk menggambarkan cara kerja sesuatu. Kami tidak bisa mendapatkan objek ini dalam kode kami dan memanipulasinya secara langsung Mesin JavaScript juga dapat mengoptimalkannya, membuang variabel yang tidak digunakan untuk menghemat memori dan melakukan trik internal lainnya, selama perilaku yang terlihat tetap seperti yang dijelaskan Fungsi juga merupakan nilai, seperti variabel Perbedaannya adalah Deklarasi Fungsi langsung diinisialisasi sepenuhnya Ketika Lingkungan Leksikal dibuat, Deklarasi Fungsi segera menjadi fungsi siap pakai (tidak seperti 4, yang tidak dapat digunakan sampai deklarasi)Itu sebabnya kita bisa menggunakan fungsi, dideklarasikan sebagai Deklarasi Fungsi, bahkan sebelum deklarasi itu sendiri Misalnya, inilah keadaan awal Lingkungan Lexical global saat kita menambahkan sebuah fungsi Secara alami, perilaku ini hanya berlaku untuk Deklarasi Fungsi, bukan Ekspresi Fungsi di mana kami menetapkan fungsi ke variabel, seperti 8Ketika suatu fungsi berjalan, pada awal panggilan, Lingkungan Lexical baru dibuat secara otomatis untuk menyimpan variabel lokal dan parameter panggilan Misalnya, untuk _9, tampilannya seperti ini (eksekusinya ada di baris, diberi tanda panah)Selama pemanggilan fungsi, kami memiliki dua Lingkungan Lexical. bagian dalam (untuk pemanggilan fungsi) dan bagian luar (global)
Lingkungan Leksikal batin memiliki referensi ke 6Ketika kode ingin mengakses variabel – Lingkungan Lexical bagian dalam dicari terlebih dahulu, lalu yang terluar, lalu yang lebih terluar dan seterusnya hingga yang global Jika variabel tidak ditemukan di mana pun, itu adalah kesalahan dalam mode ketat (tanpa 7, penugasan ke variabel yang tidak ada membuat variabel global baru, untuk kompatibilitas dengan kode lama)Dalam contoh ini hasil pencarian sebagai berikut
Mari kembali ke contoh _7
Di awal setiap panggilan _4, objek Lexical Environment baru dibuat, untuk menyimpan variabel untuk proses 7 iniJadi kami memiliki dua Lingkungan Leksikal bersarang, seperti pada contoh di atas Apa yang berbeda adalah, selama eksekusi 4, fungsi bersarang kecil dibuat hanya dari satu baris. 7. Kami belum menjalankannya, hanya membuatSemua fungsi mengingat Lingkungan Leksikal tempat mereka dibuat. Secara teknis, tidak ada keajaiban di sini. semua fungsi memiliki properti tersembunyi bernama _8, yang menyimpan referensi ke Lingkungan Lexical tempat fungsi dibuatJadi, _9 memiliki referensi ke 0 Leksikal Lingkungan. Begitulah fungsi mengingat di mana ia dibuat, di mana pun ia dipanggil. Referensi _8 disetel sekali dan selamanya pada waktu pembuatan fungsiKemudian, ketika 2 dipanggil, Lingkungan Leksikal baru dibuat untuk panggilan tersebut, dan referensi Lingkungan Leksikal luarnya diambil dari 9Sekarang ketika kode di dalam 2 mencari variabel 5, pertama-tama ia mencari Lingkungan Lexical-nya sendiri (kosong, karena tidak ada variabel lokal di sana), kemudian Lingkungan Lexical dari panggilan 4 luar, di mana ia menemukan dan mengubahnyaVariabel diperbarui di Lingkungan Lexical tempatnya berada Inilah keadaan setelah eksekusi Jika kita memanggil 2 beberapa kali, variabel 5 akan dinaikkan menjadi 9, 0 dan seterusnya, di tempat yang samaPenutupan Ada istilah pemrograman umum "penutupan", yang umumnya harus diketahui oleh pengembang Penutupan adalah fungsi yang mengingat variabel luarnya dan dapat mengaksesnya. Dalam beberapa bahasa, itu tidak mungkin, atau sebuah fungsi harus ditulis dengan cara khusus untuk mewujudkannya. Tapi seperti yang dijelaskan di atas, dalam JavaScript, semua fungsi secara alami adalah penutupan (hanya ada satu pengecualian, untuk dicakup dalam sintaks "Fungsi baru") Itu adalah. mereka secara otomatis mengingat di mana mereka dibuat menggunakan properti 8 tersembunyi, dan kemudian kode mereka dapat mengakses variabel luarKetika dalam sebuah wawancara, pengembang frontend mendapat pertanyaan tentang "apa itu penutupan?", Jawaban yang valid adalah definisi penutupan dan penjelasan bahwa semua fungsi dalam JavaScript adalah penutupan, dan mungkin beberapa kata lagi tentang detail teknis. properti _8 dan bagaimana Leksikal Lingkungan bekerjaBiasanya, Lingkungan Lexical dihapus dari memori dengan semua variabel setelah pemanggilan fungsi selesai. Itu karena tidak ada referensi untuk itu. Seperti objek JavaScript apa pun, itu hanya disimpan dalam memori saat dapat dijangkau Namun, jika ada fungsi bersarang yang masih dapat dijangkau setelah fungsi berakhir, maka fungsi tersebut memiliki properti 8 yang mereferensikan lingkungan leksikalDalam hal itu Lingkungan Leksikal masih dapat dijangkau bahkan setelah fungsi selesai, sehingga tetap hidup Sebagai contoh
Perhatikan bahwa jika 4 dipanggil berkali-kali, dan fungsi yang dihasilkan disimpan, maka semua objek Leksikal Lingkungan yang sesuai juga akan disimpan di memori. Dalam kode di bawah ini, ketiganya
Objek Lingkungan Leksikal mati ketika menjadi tidak terjangkau (sama seperti objek lainnya). Dengan kata lain, itu hanya ada jika setidaknya ada satu fungsi bersarang yang mereferensikannya Dalam kode di bawah ini, setelah fungsi bersarang dihapus, Lingkungan Lexical terlampir (dan karenanya 5) dibersihkan dari memori 0Seperti yang telah kita lihat, dalam teori saat sebuah fungsi aktif, semua variabel luar juga dipertahankan Namun dalam praktiknya, mesin JavaScript mencoba mengoptimalkannya. Mereka menganalisis penggunaan variabel dan jika jelas dari kode bahwa variabel luar tidak digunakan – itu akan dihapus Efek samping yang penting di V8 (Chrome, Edge, Opera) adalah bahwa variabel tersebut tidak akan tersedia dalam proses debug Coba jalankan contoh di bawah ini di Chrome dengan Alat Pengembang terbuka Saat dijeda, di konsol ketik 6 _1Seperti yang Anda lihat – tidak ada variabel seperti itu. Secara teori, itu harus dapat diakses, tetapi mesin mengoptimalkannya Itu dapat menyebabkan masalah debug yang lucu (jika tidak memakan waktu). Salah satunya – kita bisa melihat variabel luar dengan nama yang sama, bukan yang diharapkan _2Fitur V8 ini baik untuk diketahui. Jika Anda melakukan debug dengan Chrome/Edge/Opera, cepat atau lambat Anda akan menemukannya Itu bukan bug di debugger, melainkan fitur khusus V8. Mungkin suatu saat akan diubah. Anda selalu dapat memeriksanya dengan menjalankan contoh di halaman ini Bagaimana cara memanggil fungsi dalam di JS?Pendekatan. . Tulis satu fungsi di dalam fungsi lain Lakukan panggilan ke fungsi dalam di pernyataan pengembalian fungsi luar Sebut saja fun(a)(b) di mana a adalah parameter ke luar dan b ke fungsi dalam Terakhir, kembalikan output gabungan dari fungsi bersarang Bisakah kita memanggil fungsi di dalam fungsi dalam JavaScript?Dalam JavaScript, fungsi adalah objek kelas satu. Ini berarti mereka dapat dibuat dan digunakan seperti objek lainnya dalam bahasa. Fungsi dapat diteruskan sebagai argumen ke fungsi lain, ditetapkan ke variabel, dan bahkan dikembalikan ke fungsi lain .
Bisakah Anda memanggil fungsi di dalam fungsi?Memanggil fungsi dari dalam dirinya sendiri disebut rekursi dan jawaban sederhananya adalah, ya.
Apakah boleh meletakkan fungsi di dalam fungsi?Kita dapat mendeklarasikan sebuah fungsi di dalam sebuah fungsi, tetapi itu bukan fungsi bersarang . Karena definisi fungsi bersarang tidak dapat mengakses variabel lokal dari blok sekitarnya, mereka hanya dapat mengakses variabel global dari modul yang memuatnya. |