Perkenalan
Penutupan adalah fungsi yang memiliki izin untuk mengakses variabel dalam ruang lingkup fungsi lain.
Penutupan sulit dipahami dalam JavaScript. Banyak aplikasi canggih bergantung pada penutupan untuk mengimplementasikannya. Mari kita lihat contoh pertama di bawah ini:
fungsi luar () {var i = 100; function inner () {console.log (i); }}Dalam kode di atas, sesuai dengan ruang lingkup variabel, semua variabel lokal dalam fungsi luar terlihat oleh fungsi dalam; Variabel lokal dalam fungsi bagian dalam tidak terlihat di luar fungsi dalam, sehingga variabel lokal dalam fungsi bagian dalam tidak dapat dibaca di luar fungsi bagian dalam.
Karena fungsi dalam dapat membaca variabel lokal dari fungsi luar, selama bagian dalam digunakan sebagai nilai pengembalian, variabel lokal dalam dapat dibaca langsung di luar ouer.
fungsi luar () {var i = 100; function inner () {console.log (i); } return dalam;} var rs = outer (); rs ();Fungsi ini memiliki dua karakteristik:
Setelah mengeksekusi var rs = luar () dengan cara ini, RS aktual menunjuk ke fungsi dalam. Kode ini sebenarnya merupakan penutupan. Artinya, ketika fungsi bagian dalam di dalam fungsi luar dirujuk oleh variabel di luar fungsi luar, penutupan dibuat.
Cakupan
Sederhananya, ruang lingkup adalah kisaran variabel dan fungsi yang dapat diakses, yaitu, ruang lingkup mengontrol visibilitas dan siklus hidup variabel dan fungsi. Dalam JavaScript, ruang lingkup variabel bersifat global dan lokal.
Ruang lingkup global
var num1 = 1; fungsi fun1 () {num2 = 2;}Tiga objek di atas NUM1, NUM2 dan FUN1 adalah semua lingkup global. Perlu dicatat di sini bahwa variabel yang mendefinisikan penugasan langsung pada akhirnya secara otomatis dinyatakan memiliki lingkup global;
Ruang lingkup lokal
function wrap () {var obj = "Saya terbungkus dengan bungkus, dan bagian luar bungkus tidak dapat secara langsung mengakses saya"; fungsi innerfun () {// luar tidak dapat mengakses saya}}Rantai Lingkup
Segala sesuatu dalam JavaScript adalah objek. Objek -objek ini memiliki properti [Lingkup]], yang berisi kumpulan objek dalam ruang lingkup yang dibuat oleh fungsi. Koleksi ini disebut rantai ruang lingkup fungsi, yang menentukan data mana yang dapat diakses oleh fungsi.
fungsi add (a, b) {return a+b;}Saat fungsi dibuat, properti [SCOPE]] akan secara otomatis menambahkan ruang lingkup global
var sum = add (3,4);
Ketika suatu fungsi dipanggil, objek internal yang disebut konteks eksekusi dibuat. Objek Z ini mendefinisikan lingkungan ketika fungsi dieksekusi. Ini juga memiliki rantai ruang lingkupnya sendiri untuk resolusi pengidentifikasi, dan rantai ruang lingkupnya diinisialisasi sebagai objek yang terkandung dalam [[ruang lingkup]] dari fungsi berjalan saat ini.
Selama eksekusi fungsi, setiap kali variabel ditemui, proses pengenal pengenal akan diteruskan untuk memutuskan di mana harus mendapatkan dan menyimpan data. Proses ini dimulai dari kepala rantai ruang lingkup, yaitu mencari pengidentifikasi dengan nama yang sama dari objek aktif. Jika ditemukan, gunakan variabel yang sesuai dengan pengidentifikasi ini. Jika tidak ditemukan, terus cari objek berikutnya dalam rantai lingkup, jika semua objek dicari (yang terakhir adalah objek global) tidak ditemukan, pengidentifikasi dianggap tidak terdefinisi.
Penutup
Penutupan hanyalah suatu fungsi yang mengakses variabel eksternalnya.
var quo = function (status) {return {getstatus: function () {return status; }}}Status disimpan dalam quo, ia mengembalikan objek, metode GetStatus dalam objek ini mengacu pada variabel status, yaitu fungsi GetStatus mengakses status variabel eksternal;
var newValue = quo ('string'); // kembalikan objek anonim, dirujuk oleh newValue dengan newValue.getStatus (); // mengakses status variabel internal quoJika metode GetStatus tidak tersedia, maka status akan secara otomatis didaur ulang setelah quo ('sengatan'). Justru karena objek anonim yang dikembalikan dirujuk oleh objek global, dan objek anonim tergantung pada status, sehingga akan mencegah pelepasan status.
contoh:
// skema kesalahan var test = fungsi (node) {var i; untuk (i = 0; i <nodes.length; i ++) {node [i] .Onclick = function (e) {waspada (i); }}}Fungsi anonim menciptakan penutupan, dan I yang diakses adalah I dalam fungsi uji eksternal, sehingga setiap node benar -benar mengacu pada i yang sama.
// Solusi peningkatan var test = fungsi (node) {var i; untuk (i = 0; i <nodes.length; i ++) {node [i] .Onclick = function (i) {return function () {waspada (i); }; }(Saya); }}Setiap node terikat pada suatu acara. Acara ini menerima parameter dan berjalan segera, lulus dalam i. Karena diteruskan berdasarkan nilai, setiap loop akan menghasilkan cadangan baru untuk saat ini i.
Peran Penutupan
fungsi luar () {var i = 100; function inner () {console.log (i ++); } return dalam;} var rs = outer (); rs (); // 100rs (); // 101rs (); // 102Dalam kode di atas, RS adalah fungsi penutup dalam. RS berlari tiga kali secara total, pertama kali adalah 100, kedua kalinya adalah 101, dan ketiga kalinya adalah 102. Ini menunjukkan bahwa variabel lokal I dalam fungsi luar telah disimpan dalam memori dan tidak secara otomatis dibersihkan ketika dipanggil.
Tujuan penutupannya adalah bahwa setelah eksekusi luar selesai dan dikembalikan, penutupan membuat mekanisme pengumpulan sampah Javascript (koleksi grabage) tidak mendaur ulang memori yang ditempati oleh luar, karena pelaksanaan fungsi dalam bagian luar tergantung pada variabel di luar. (Penjelasan lain: luar adalah fungsi induk dari dalam, bagian dalam ditugaskan ke variabel global, menyebabkan bagian dalam dalam memori sepanjang waktu, dan keberadaan bagian dalam tergantung pada bagian luar, karena beberapa luar selalu dalam memori dan tidak akan dikumpulkan dan didaur ulang setelah panggilan selesai).
Penutupan memiliki izin untuk mengakses semua variabel di dalam fungsi.
Ketika suatu fungsi mengembalikan penutupan, ruang lingkup fungsi akan disimpan dalam memori sampai penutupan tidak ada.
Penutupan dan variabel
Karena mekanisme rantai lingkup, penutupan hanya bisa mendapatkan nilai terakhir yang berisi variabel apa pun dalam fungsi. Lihat contoh berikut:
fungsi f () {var rs = []; untuk (var i = 0; i <10; i ++) {rs [i] = function () {return i; }; } return rs;} var fn = f (); untuk (var i = 0; i <fn.length; i ++) {console.log ('function fn [' + i + '] () nilai pengembalian:' + fn [i] ());}Fungsi akan mengembalikan array. Di permukaan, tampaknya setiap fungsi harus mengembalikan nilai indeksnya sendiri. Bahkan, setiap fungsi mengembalikan 10. Ini karena rantai ruang lingkup fungsi pertama berisi objek aktif fungsi f, dan mereka merujuk ke variabel yang sama i. Ketika fungsi F mengembalikan, nilai variabel i adalah 10. Pada saat ini, setiap fungsi menyimpan objek variabel yang sama dari variabel i. Kita dapat memaksa penutupan untuk berperilaku seperti yang diharapkan dengan menciptakan fungsi anonim lainnya.
fungsi f () {var rs = []; untuk (var i = 0; i <10; i ++) {rs [i] = function (num) {return function () {return num; }; }(Saya); } return rs;} var fn = f (); untuk (var i = 0; i <fn.length; i ++) {console.log ('function fn [' + i + '] () nilai pengembalian:' + fn [i] ());}Dalam versi ini, alih -alih menetapkan penutupan ke array secara langsung, kami mendefinisikan fungsi anonim dan menetapkan hasil dari segera menjalankan fungsi anonim ke array. Di sini, fungsi anonim memiliki num parameter. Saat memanggil setiap fungsi, kami lulus dalam variabel i. Karena parameter dilewatkan berdasarkan nilai, variabel saya akan disalin ke parameter num. Di dalam fungsi anonim ini, penutupan pengaksaan NUM dibuat dan dikembalikan. Dengan cara ini, setiap fungsi dalam array RS memiliki salinan variabel NUM sendiri, sehingga nilai yang berbeda dapat dikembalikan.
Objek ini sebagai penutup
var name = 'jack'; var o = {name: 'bingdian', getName: function () {return function () {return this.name; }; }} console.log (o.getName () () ()); // jackvar name = 'jack'; var o = {name: 'bingdian', getName: function () {var self = this; return function () {return self.name; }; }} console.log (o.getName () () ()); // BingdianBocor memori
function assignhandler () {var el = document.geteLementById ('demo'); el.onClick = function () {console.log (el.id); }} assignhandler ();Kode di atas menciptakan penutupan sebagai penangan acara elemen el, dan penutupan ini membuat referensi melingkar. Selama fungsi anonim ada, jumlah referensi EL setidaknya 1, karena memori yang ditempati tidak akan pernah didaur ulang.
function assignhandler () {var el = document.geteLementById ('demo'); var id = el.id; el.onClick = function () {console.log (id); } el = null;} assignhandler ();Menetapkan variabel el null dapat dereferensi objek DOM dan memastikan bahwa ia mengkonsumsi memori secara normal.
Meniru ruang lingkup tingkat blok
Pernyataan yang ditetapkan dalam setiap kawat gigi keriting ({dan}) milik blok, dan semua variabel yang ditentukan dalam hal ini tidak terlihat di luar blok kode, yang kami sebut lingkup level blok.
(function () {// block-level scope}) ();Penerapan penutupan
Lindungi keamanan variabel dalam fungsi. Seperti pada contoh sebelumnya, hanya fungsi dalam yang dapat mengakses I di luar fungsi, tetapi tidak dapat diakses melalui saluran lain, sehingga melindungi keamanan i.
Pertahankan variabel dalam memori. Seperti pada contoh sebelumnya, karena penutupan, i dalam fungsi luar selalu ada dalam memori, jadi setiap kali RS () dieksekusi, saya akan ditambahkan 1.