Pendahuluan: Ini masih merupakan artikel pengantar. Ada beberapa fitur bahasa yang sangat penting dalam JavaScript - objek, pewarisan prototipe, dan penutupan. Di antara mereka, penutupan adalah fitur bahasa baru untuk pemrogram yang menggunakan bahasa statis tradisional C/C ++. Artikel ini akan dimulai dengan contoh -contoh untuk memperkenalkan fitur bahasa penutupan javascript, dan menggabungkan beberapa spesifikasi bahasa ecmascript untuk memungkinkan pembaca memahami penutupan lebih dalam.
Catatan: Artikel ini adalah artikel pengantar, dan contoh materi disusun di Internet. Jika Anda seorang master, Anda dipersilakan untuk mengajukan saran teknis dan pendapat pada artikel tersebut. Artikel ini membahas JavaScript, dan Anda tidak ingin membandingkan bahasa. Jika Anda secara alami tidak nyaman dengan JavaScript, silakan mengambil jalan memutar.
Apa itu penutupan
Apa itu penutupan? Penutupan adalah penutupan, yang merupakan fitur baru yang tidak dimiliki bahasa statis. Tetapi penutupan bukanlah sesuatu yang sangat rumit sehingga tidak dapat dipahami. Singkatnya, penutupan adalah:
Penutupan adalah himpunan variabel lokal fungsi, tetapi variabel lokal ini akan terus ada setelah fungsi kembali.
Penutupan adalah "tumpukan" fungsi dan tidak dirilis setelah fungsi kembali. Kami juga dapat memahami bahwa tumpukan fungsi ini tidak dialokasikan pada tumpukan tetapi dialokasikan pada tumpukan.
Saat mendefinisikan fungsi lain dalam suatu fungsi, penutupan akan dihasilkan
Definisi kedua di atas adalah deskripsi tambahan pertama, yang mengekstraksi objek subjek -predikat dari definisi pertama - penutupan adalah seperangkat 'variabel lokal' fungsi. Hanya saja variabel lokal ini dapat diakses setelah fungsi kembali. (Ini bukan definisi resmi, tetapi definisi ini harus lebih kondusif untuk pemahaman Anda tentang penutupan)
Sebagai variabel lokal, mereka dapat diakses oleh kode dalam fungsi, dan tidak ada perbedaan antara ini dan bahasa statis. Perbedaan antara penutupan adalah bahwa variabel lokal masih dapat diakses dengan kode di luar fungsi setelah fungsi dieksekusi. Ini berarti bahwa fungsi harus mengembalikan "referensi" ke penutupan, atau menetapkan "referensi" ini ke variabel eksternal untuk memastikan bahwa variabel lokal dalam penutupan diakses oleh kode eksternal. Tentu saja, entitas yang berisi referensi ini harus menjadi objek, karena dalam JavaScript, semua yang lain kecuali tipe dasar adalah objek. Sayangnya, ecmascript tidak menyediakan anggota dan metode yang relevan untuk mengakses variabel lokal dalam penutupan. Namun, dalam ecmascript, fungsi dalam yang didefinisikan dalam objek fungsi adalah variabel lokal yang dapat secara langsung mengakses fungsi eksternal. Melalui mekanisme ini, kita dapat menyelesaikan akses ke penutupan dengan cara berikut.
Salinan kode adalah sebagai berikut:
function ucapan (name) {
var text = 'hello' + name; // variabel lokal
// Setiap kali penutupan dihasilkan, dan objek fungsi internal dikembalikan ke penelepon
return function () {alert (teks); }
}
var sayshello = ucapan ("penutupan");
Sayshello () // Akses teks variabel lokal melalui penutupan
Hasil eksekusi dari kode di atas adalah: halo penutupan, karena setelah fungsi ucapan dieksekusi, fungsi sayhello () masih dapat mengakses teks variabel lokal yang ditentukan di dalamnya.
Oke, ini adalah efek dari penutupan legendaris. Penutupan memiliki banyak skenario dan mode aplikasi dalam JavaScript, seperti Singleton, Power Constructor, dan mode JavaScript lainnya yang tidak dapat dipisahkan dari penggunaan penutupan.
Model penutupan ecmascript
Bagaimana ECMascript menerapkan penutupan? Jika Anda ingin memiliki pemahaman mendalam, Anda dapat memperoleh spesifikasi ecmascript untuk penelitian. Saya hanya akan memberikan penjelasan sederhana di sini, dan kontennya juga berasal dari internet.
Ketika fungsi skrip ecmascript berjalan, setiap asosiasi fungsi memiliki skenario konteks eksekusi (konteks eksekusi), yang berisi tiga bagian.
Lexicalenvironment
Variabelsvironment
Ikatan ini
Poin ketiga dari ikatan ini tidak ada hubungannya dengan penutupan dan tidak dibahas dalam artikel ini. Pengidentifikasi variabel yang digunakan dalam lingkungan tata bahasa untuk mem -parsing proses eksekusi fungsi. Kita dapat menganggap lingkungan tata bahasa sebagai objek yang berisi dua komponen penting, catatan lingkungan (Recode Enviroment), dan referensi eksternal (pointer). Catatan lingkungan berisi variabel lokal dan variabel parameter yang dinyatakan secara internal oleh fungsi, dan referensi eksternal menunjuk ke skenario eksekusi konteks objek fungsi eksternal. Nilai referensi ini nol dalam skenario konteks global. Struktur data seperti itu membentuk daftar tertaut satu arah, masing-masing referensi menunjuk ke skenario konteks luar.
Misalnya, model penutupan dalam contoh kami di atas harus seperti ini. Fungsi Sayhello berada pada level terendah, level atas adalah salam fungsi, dan level terluar adalah adegan global. Seperti yang ditunjukkan pada gambar di bawah ini: Oleh karena itu, ketika Sayshello dipanggil, Sayshello akan menemukan nilai teks variabel lokal melalui adegan konteks, sehingga lingkungan variabel "hello penutupan" (lingkungan variabel) dan lingkungan tata bahasa pada dasarnya sama. Untuk perbedaan spesifik, silakan merujuk ke dokumen spesifikasi ecmascript.
Contoh kolom penutupan
Dalam artikel sebelumnya, saya secara kasar mengerti apa itu penutupan javascript dan bagaimana penutupan diimplementasikan dalam JavaScript. Di bawah ini kami akan membantu Anda memahami penutupan lebih dalam dengan menargetkan beberapa contoh. Ada 5 contoh di bawah ini, dan contohnya dari penutupan javascript untuk boneka (cermin). Contoh 1: Variabel lokal dalam penutupan adalah referensi daripada salinan
Salinan kode adalah sebagai berikut:
fungsi mengatakan667 () {
// variabel lokal yang berakhir dalam penutupan
var num = 666;
var sayalert = function () {alert (num); }
num ++;
Kembalikan Saysalert;
}
var Sayalert = Say667 ();
Sayalert ()
Oleh karena itu, hasil eksekusi harus muncul 667, bukan 666.
Contoh 2: Beberapa fungsi mengikat penutupan yang sama karena mereka didefinisikan dalam fungsi yang sama.
Salinan kode adalah sebagai berikut:
function setupsomeglobals () {
// variabel lokal yang berakhir dalam penutupan
var num = 666;
// Simpan beberapa referensi ke fungsi sebagai variabel global
galertNumber = function () {alert (num); }
gincreaseNumber = function () {num ++; }
gsetNumber = function (x) {num = x; }
}
setupsomeglobals (); // Tetapkan nilai ke tiga variabel global
galertnumber (); // 666
Gincreasenumber ();
galertnumber (); // 667
GSetNumber (12); //
galertnumber (); // 12
Contoh 3: Saat menetapkan fungsi dalam satu loop, fungsi -fungsi ini akan mengikat penutupan yang sama
Salinan kode adalah sebagai berikut:
fungsi buildlist (daftar) {
var result = [];
untuk (var i = 0; i <list.length; i ++) {
var item = 'item' + list [i];
result.push (function () {alert (item + '' + list [i])});
}
hasil pengembalian;
}
function testList () {
var fnlist = buildlist ([1,2,3]);
// menggunakan j hanya untuk membantu mencegah kebingungan - bisa menggunakan i
untuk (var j = 0; j <fnlist.length; j ++) {
fnlist [j] ();
}
}
Hasil eksekusi dari TestList adalah bahwa jendela yang tidak ditentukan item3 muncul tiga kali, karena ketiga fungsi ini mengikat penutupan yang sama, dan nilai item adalah hasil yang dihitung terakhir, tetapi ketika saya melompat keluar dari loop, nilai I adalah 4, jadi hasil dari daftar [4] tidak ditentukan.
Contoh 4: Semua variabel lokal fungsi eksternal berada dalam penutupan, bahkan jika variabel ini dinyatakan setelah definisi fungsi internal.
Salinan kode adalah sebagai berikut:
function sadalice () {
var sayalert = function () {waspada (alice); }
// variabel lokal yang berakhir dalam penutupan
var Alice = 'Hello Alice';
Kembalikan Saysalert;
}
var helloalice = wayalice ();
helloalice ();
Hasil eksekusi adalah jendela dengan pop-up "Hello Alice". Bahkan jika variabel lokal menyatakan setelah fungsi kata -kata, variabel lokal masih dapat diakses.
Contoh 5: Buat penutupan baru setiap kali fungsi disebut
Salinan kode adalah sebagai berikut:
function newclosure (somenum, someref) {
// Variabel lokal yang berakhir dalam penutupan
var num = somenum;
var anarray = [1,2,3];
var ref = someref;
return function (x) {
num += x;
anarray.push (num);
peringatan ('num:' + num +
'/nanarray' + anarray.tostring () +
'/nref.somevar' + ref.somevar);
}
}
closure1 = newclosure (40, {somevar: 'closure 1'});
closure2 = newclosure (1000, {somevar: 'closure 2'});
penutupan1 (5); // num: 45 Anarray [1,2,3,45] Ref: 'Somevar Closure1'
closure2 (-10); // num: 990 anarray [1,2,3,990] ref: 'somevar closure2'
Penerapan penutupan
Singleton Single Piece:
Salinan kode adalah sebagai berikut:
var singleton = function () {
var privatevariable;
function privateFunction (x) {
... Privatevariable ...
}
kembali {
firstmethod: function (a, b) {
... Privatevariable ...
},
SecondMethod: function (c) {
... privateFunction () ...
}
};
} ();
Potongan tunggal ini dicapai melalui penutupan. Enkapsulasi anggota dan metode pribadi diselesaikan melalui penutupan. Fungsi utama anonim mengembalikan suatu objek. Objek ini berisi dua metode, Metode 1 dapat menggunakan variabel pribadi, dan Metode 2 dapat mengakses fungsi pribadi internal. Hal yang perlu diperhatikan adalah '()' di mana fungsi utama anonim berakhir. Tanpa ini '()', satu bagian tidak dapat diproduksi. Karena fungsi anonim hanya dapat mengembalikan objek unik dan tidak dapat disebut di tempat lain. Ini adalah metode menggunakan penutupan untuk menghasilkan potongan tunggal.