Mengisi kembali:
Penutupan adalah kesulitan dalam bahasa JavaScript dan fiturnya. Banyak aplikasi canggih bergantung pada penutupan untuk diterapkan.
Fitur Penutupan
Penutupan memiliki tiga karakteristik:
1. Fungsi fungsi bersarang
2. Fungsi dapat merujuk ke parameter dan variabel eksternal di dalamnya
3. Parameter dan variabel tidak akan dikumpulkan oleh mekanisme pengumpulan sampah
Definisi penutupan dan kelebihan serta kerugiannya
Penutupan merujuk pada fungsi yang memiliki akses ke variabel dalam ruang lingkup fungsi lain. Cara paling umum untuk membuat penutupan adalah dengan membuat fungsi lain dalam satu fungsi dan mengakses variabel lokal fungsi ini melalui fungsi lain.
Kerugian dari penutupan adalah bahwa mereka adalah memori penduduk, yang akan meningkatkan penggunaan memori, dan penggunaan yang tidak tepat dapat dengan mudah menyebabkan kebocoran memori.
Penutupan adalah fitur utama dari bahasa JavaScript. Aplikasi utama penutupan terutama untuk: merancang metode dan variabel pribadi.
Setelah fungsi umum dijalankan, objek aktif lokal dihancurkan dan hanya ruang lingkup global yang disimpan dalam memori. Tapi situasi penutupan berbeda!
Untuk membicarakan topiknya
1. Definisi penutupan?
Mari kita lihat beberapa definisi tentang penutupan:
1. Penutupan mengacu pada fungsi yang memiliki izin untuk mengakses variabel dalam ruang lingkup fungsi lain.
2. Objek fungsi dapat dikaitkan melalui rantai lingkup, dan variabel di dalam tubuh fungsi dapat disimpan dalam ruang lingkup fungsi. Karakteristik ini disebut 'penutupan'.
3. Fungsi internal dapat mengakses parameter dan variabel fungsi eksternal yang mendefinisikannya (kecuali ini dan argumen).
Jika Anda ingin secara sistematis mempelajari konsep penutupan JS, Anda dapat merujuk ke kolom e-book JS dari situs web Wulin.com untuk dipelajari.
Mari kita ringkas definisi
1. Anda dapat mengakses fungsi variabel dalam lingkup fungsi eksternal
2. Variabel fungsi eksternal yang diakses oleh fungsi internal dapat disimpan dalam ruang lingkup fungsi eksternal tanpa didaur ulang-ini adalah intinya. Kemudian, ketika kita mengalami penutupan, kita harus memikirkannya. Kita harus fokus pada variabel yang dirujuk oleh penutupan.
Buat penutupan sederhana
var Sayname = function () {var name = 'jozo'; return function () {alert (name);}}; var mengatakan = sayname (); mengatakan();Mari kita menafsirkan dua kalimat berikutnya:
• var mengatakan = sayname (): Mengembalikan fungsi internal anonim yang disimpan dalam variabel mengatakan dan mengacu pada nama variabel fungsi eksternal. Karena mekanisme pengumpulan sampah, setelah fungsi Sayname dieksekusi, nama variabel tidak dihancurkan.
• say (): Jalankan fungsi internal yang dikembalikan, dan masih mengakses nama variabel dan output 'Jozo'.
2. Rantai SCOPE Tutup
Memahami Rantai Lingkup juga bermanfaat untuk memahami penutupan.
Metode pencarian variabel dalam ruang lingkup harus sangat akrab, tetapi pada kenyataannya, inilah yang mencari ke atas di sepanjang rantai lingkup.
Saat fungsinya disebut:
1. Pertama buat konteks eksekusi dan rantai ruang lingkup yang sesuai;
2. Tambahkan argumen dan nilai parameter bernama lainnya ke objek aktif fungsi (objek aktivasi)
Rantai Lingkup: Objek aktif dari fungsi saat ini memiliki prioritas tertinggi, diikuti oleh objek aktif fungsi eksternal, dan objek aktif dari fungsi eksternal fungsi eksternal berkurang secara berurutan hingga akhir rantai lingkup - ruang lingkup global. Prioritas adalah urutan pencarian variabel;
Pertama -tama mari kita lihat rantai lingkup normal:
function Sayname (name) {return name;} var mengatakan = sayname ('jozo');Kode ini berisi dua lingkup: a. ruang lingkup global; B.Sayname Fungsi Lingkup, yaitu, hanya ada dua objek variabel. Ketika dieksekusi ke lingkungan eksekusi yang sesuai, objek variabel akan menjadi objek aktif dan didorong ke ujung depan rantai ruang lingkup lingkungan eksekusi, yaitu, itu menjadi prioritas tertinggi. Bicaralah dengan gambar:
Gambar ini juga tersedia dalam buku pemrograman lanjutan JS, dan saya telah menggambar ulang semuanya.
Saat membuat fungsi SayName (), rantai lingkup yang berisi objek variabel di muka dibuat, yaitu, rantai lingkup yang diindeks oleh 1 pada gambar, dan disimpan dalam atribut internal [[lingkup]]. Ketika fungsi SayName () dipanggil, lingkungan eksekusi dibuat, dan kemudian rantai lingkup dibangun dengan menyalin objek dalam atribut [[lingkup]] fungsi. Setelah itu, objek aktif lainnya (diindeks oleh 0 pada gambar) dibuat dan didorong ke ujung depan rantai lingkup lingkungan eksekusi.
Secara umum, ketika fungsi dieksekusi, objek aktif lokal akan dihancurkan dan hanya ruang lingkup global yang disimpan dalam memori. Namun, situasi penutupan berbeda:
Mari kita lihat rantai ruang lingkup penutupan:
function wissname (name) {return function () {return name;}} var bilang = sayname ('jozo');Contoh penutupan ini memiliki satu ruang lagi untuk fungsi anonim dari contoh sebelumnya:
Setelah fungsi anonim dikembalikan dari fungsi SayName (), rantai lingkupnya diinisialisasi ke objek aktif dan objek variabel global yang berisi fungsi SayName (). Dengan cara ini, fungsi anonim dapat mengakses semua variabel dan parameter yang didefinisikan dalam SayName (). Lebih penting lagi, setelah pelaksanaan fungsi SayName (), objek aktifnya tidak akan dihancurkan, karena rantai ruang lingkup fungsi anonim masih mengacu pada objek aktif. Dengan kata lain, setelah eksekusi fungsi SayName (), rantai ruang lingkup lingkungan eksekusi akan dihancurkan, tetapi objek aktifnya akan ditinggalkan dalam ingatan, mengetahui bahwa fungsi anonim akan dihancurkan. Ini juga masalah kebocoran memori yang akan dibahas nanti.
Saya tidak banyak menulis tentang masalah rantai ruang lingkup, dan menulis hal -hal dalam buku ini juga sangat melelahkan o (□) o
3. Contoh penutupan
Contoh 1: Implementasi akumulasi
// Metode 1var a = 0; var add = function () {a ++; console.log (a)} add (); add (); // metode 2: penutupan var add = (function () {var a = 0; return function () {a ++; console.log (a);}}) (); console.log (a ++; console.log (a);}}) (); console.log (a); // undefinedadd (); add ();Sebagai perbandingan, Metode 2 lebih elegan, dan juga mengurangi variabel global, dan memprivatisasi variabel.
Contoh 2: Tambahkan Klik Acara ke setiap LI
var oli = document.geteLementsByTagname ('li'); var i; for (i = 0; i <5; i ++) {oli [i] .Onclick = function () {warting (i);}} konsol.log (i); // 5 // Jalankan fungsi anonim (function () {alert (i); // 5} ());Di atas adalah contoh klasik. Kita semua tahu bahwa hasil eksekusi adalah bahwa 5 muncul, dan kita juga tahu bahwa penutupan dapat digunakan untuk menyelesaikan masalah ini, tetapi pada awalnya, saya masih tidak mengerti mengapa 5 muncul dan mengapa penutupan dapat menyelesaikan masalah ini. Kemudian, saya menyelesaikannya dan menjelaskannya:
A. Pertama -tama mari kita menganalisis situasi sebelum penutupan digunakan: dalam loop untuk, kita mengikat fungsi anonim untuk setiap acara klik li, dan nilai variabel yang saya kembalikan dalam fungsi anonim. Ketika loop berakhir, nilai variabel I menjadi 5. Pada saat ini, kami mengklik setiap li, yaitu, jalankan fungsi anonim yang sesuai (lihat kode di atas). Ini adalah variabel yang sudah saya lakukan 5, jadi setiap klik muncul 5. Karena setiap fungsi anonim yang dikembalikan di sini mengacu pada variabel yang sama i, jika kita membuat variabel baru untuk menyimpan nilai i saat ini dari i ketika loop dieksekusi, maka biarkan fungsi anonim menerapkan variabel ini, dan akhirnya mengembalikan fungsi anonim ini, sehingga tujuan kita dapat dicapai. Ini dicapai dengan menggunakan penutupan!
B. Mari kita analisis situasi saat menggunakan penutupan:
var oli = document.geteLementsbyTagname ('li'); var i; for (i = 0; i <5; i ++) {oli [i] .onClick = (function (num) {var a = num; // Untuk mengilustrasikan fungsi pengembalian masalah () {a);}}) (i)} console.log (i) (i); // 5Ketika loop untuk dieksekusi, fungsi anonim yang terikat pada acara klik dilewatkan saya dan segera dieksekusi untuk mengembalikan fungsi anonim internal. Karena parameter dilewatkan berdasarkan nilai, parameter formal NUM menghemat nilai saat ini dari i, dan kemudian memberikan nilai ke variabel lokal a. Kemudian fungsi anonim internal membuat referensi a, yaitu, menjaga nilai i saat ini. Jadi setelah loop dieksekusi, klik masing -masing Li, dan fungsi anonim yang dikembalikan akan memunculkan nilai yang disimpan a.
4. Penerapan penutupan
Mari kita lihat tujuan penutupan. Bahkan, dengan menggunakan penutupan, kita dapat melakukan banyak hal. Misalnya, simulasikan gaya kode yang berorientasi objek; kode ekspres lebih elegan dan ringkas; dan meningkatkan efisiensi eksekusi kode dalam beberapa aspek.
1. Fungsi pengendalian diri anonim
Dalam situasi yang sebenarnya, kita sering menghadapi situasi di mana beberapa fungsi hanya perlu dieksekusi sekali dan variabel internal mereka tidak perlu dipertahankan, seperti inisialisasi UI, sehingga kita dapat menggunakan penutupan:
// Ubah semua Li font menjadi merah (function () {var els = document.geteLementsbyTagname ('li'); for (var i = 0, lng = els.length; i <lng; i ++) {els [i] .style.color = 'merah';}}) ();Kami membuat fungsi anonim dan menjalankannya segera. Karena eksternal tidak dapat merujuk ke variabel di dalamnya, variabel lokal seperti ELS, I, dan LNG akan dirilis segera setelah eksekusi, menyimpan memori!
Kuncinya adalah bahwa mekanisme ini tidak akan mencemari objek global.
2. Menerapkan enkapsulasi/kode modular
var person = function () {// Lingkup variabel berada di dalam fungsi, dan var name = "default" tidak dapat diakses di luar. return {getName: function () {return name; }, setName: function (newName) {name = newName; }}} (); console.log (person.name); // akses langsung, hasilnya adalah console.log (person.getname ()) yang tidak terdefinisi; // default person.setname ("jozo"); console.log (person.getName ()); // Jozo3. Menerapkan berorientasi objek
Dengan cara ini, objek yang berbeda (contoh kelas) memiliki anggota dan negara bagian independen dan tidak saling mengganggu. Meskipun tidak ada mekanisme seperti kelas dalam JavaScript, dengan menggunakan penutupan, kita dapat mensimulasikan mekanisme seperti itu. Mari kita bicara tentang contoh di atas:
function person () {var name = "default"; return {getName: function () {return name; }, setName: function (newName) {name = newName; }}}; var person1 = orang (); print (person1.getName ()); John.setname ("Person1"); print (person1.getName ()); // orang1 var person2 = orang (); print (person2.getname ()); jack.setname ("erson2"); print (erson2.getname ()); // person2Dua instance orang, 1 dan orang2 tidak saling mengganggu! Karena kedua contoh ini memiliki akses independen ke anggota nama.
5. Kebocoran dan solusi memori
Mekanisme daur ulang sampah
Berbicara tentang manajemen memori, secara alami tidak dapat dipisahkan dari mekanisme pengumpulan sampah di JS. Ada dua strategi untuk mewujudkan pengumpulan sampah: tanda izin dan penghitungan referensi ;
Mark Removal: Ketika pengumpul sampah berjalan, itu akan menandai semua variabel yang disimpan dalam memori. Kemudian, itu akan menghapus tag variabel di lingkungan dan tag variabel yang dirujuk oleh variabel di lingkungan. Setelah itu, jika variabel ditandai lagi, itu berarti bahwa variabel siap dihapus. Hingga 2008, IE, Firefox, Opera, Chrome, dan JavaScript Safari semuanya menggunakan metode ini;
Hitungan referensi: Lacak berapa kali setiap nilai dirujuk. Ketika suatu variabel dinyatakan dan nilai jenis referensi ditetapkan untuk variabel, berapa kali nilai ini dirujuk adalah 1. Jika nilai ini ditugaskan ke variabel lain, berapa kali referensi meningkat sebesar 1. Sebaliknya, jika variabel menyimpang dari referensi nilai, jumlah rujukan nilainya dikurangi oleh 1, dan ketika jumlah kali.
Masalah besar dengan metode ini adalah referensi melingkar, yaitu objek A berisi pointer ke B, dan Object B juga berisi referensi ke A. Ini dapat menyebabkan sejumlah besar memori didaur ulang (kebocoran memori), karena referensi mereka tidak akan pernah 0. Dalam versi IE awal (IE4-IE6) mengadopsi mekanisme koleksi tempat yang dihitung. Salah satu alasan mengapa penutupan menyebabkan kebocoran memori adalah cacat dari algoritma ini.
Kita tahu bahwa beberapa objek di IE bukan objek JavaScript asli. Misalnya, objek dalam BOM dan DOM diimplementasikan dalam bentuk objek COM, dan mekanisme pengumpulan sampah dari objek COM mengadopsi penghitungan referensi. Oleh karena itu, meskipun mesin JavaScript IE mengadopsi strategi kliring tag, mengakses objek COM masih didasarkan pada penghitungan referensi, jadi selama objek COM dirancang di IE, akan ada masalah referensi melingkar!
Ambil kastanye:
window.onload = function () {var el = document.geteLementById ("id"); el.onClick = function () {waspada (el.id);}}Mengapa kode ini menyebabkan bocor memori?
el.onClick = function () {alert (el.id);};Saat mengeksekusi kode ini, objek fungsi anonim ditetapkan ke atribut EL; Kemudian fungsi anonim mengacu pada objek EL di dalam, dan ada referensi melingkar, sehingga tidak dapat didaur ulang;
Larutan:
window.onload = function () {var el = document.geteLementById ("id"); var id = el.id; // unreFerence el.onClick = function () {alert (id); } el = null; // Bersihkan objek aktif dalam fungsi eksternal yang dirujuk oleh penutupan}Di atas adalah ringkasan pengetahuan yang relevan tentang kebocoran memori pengumpulan pengumpulan rantai ruang lingkup rantai js yang diperkenalkan kepada Anda oleh editor. Saya harap ini akan membantu semua orang!