Bagaimana Anda menjelaskan penutupan JavaScript kepada seseorang dengan pengetahuan tentang konsep-konsep yang dikandungnya (misalnya fungsi, variabel, dan sejenisnya), tetapi tidak memahami penutupan sendiri?
Saya telah melihat contoh Skema yang diberikan di Wikipedia, tetapi sayangnya itu tidak membantu.
closure
kode yang sulit dibaca ini dibandingkan denganObject Literal
yang menggunakan kembali sendiri dan mengurangi biaya overhead yang sama, namun membutuhkan 100% lebih sedikit kode pembungkus.Jawaban:
Penutupan adalah pasangan dari:
Lingkungan leksikal adalah bagian dari setiap konteks eksekusi (stack frame), dan merupakan peta antara pengidentifikasi (mis. Nama variabel lokal) dan nilai.
Setiap fungsi dalam JavaScript mempertahankan referensi ke lingkungan leksikal luarnya. Referensi ini digunakan untuk mengkonfigurasi konteks eksekusi yang dibuat ketika suatu fungsi dipanggil. Referensi ini memungkinkan kode di dalam fungsi untuk "melihat" variabel yang dideklarasikan di luar fungsi, terlepas dari kapan dan di mana fungsi dipanggil.
Jika suatu fungsi dipanggil oleh fungsi, yang pada gilirannya disebut oleh fungsi lain, maka rantai referensi ke lingkungan leksikal luar dibuat. Rantai ini disebut rantai lingkup.
Dalam kode berikut,
inner
membentuk penutupan dengan lingkungan leksikal dari konteks eksekusi yang dibuat saatfoo
dipanggil, ditutup oleh variabelsecret
:Dengan kata lain: dalam JavaScript, fungsi membawa referensi ke "kotak negara" pribadi, yang hanya dapat diakses oleh mereka (dan fungsi lain yang dinyatakan dalam lingkungan leksikal yang sama). Kotak negara ini tidak terlihat oleh penelepon fungsi, memberikan mekanisme yang sangat baik untuk menyembunyikan data dan enkapsulasi.
Dan ingat: fungsi-fungsi dalam JavaScript dapat ditularkan seperti variabel (fungsi kelas satu), yang berarti pasangan fungsi dan keadaan ini dapat diteruskan ke program Anda: mirip dengan cara Anda memberikan instance kelas di C ++.
Jika JavaScript tidak memiliki penutupan, maka lebih banyak negara harus dilewati antara fungsi secara eksplisit , membuat daftar parameter lebih lama dan kode ribut.
Jadi, jika Anda ingin fungsi selalu memiliki akses ke bagian pribadi negara, Anda bisa menggunakan penutupan.
... dan sering kita lakukan ingin negara bergaul dengan fungsi. Misalnya, dalam Java atau C ++, ketika Anda menambahkan variabel instance pribadi dan metode ke kelas, Anda mengasosiasikan status dengan fungsionalitas.
Dalam C dan sebagian besar bahasa umum lainnya, setelah fungsi kembali, semua variabel lokal tidak lagi dapat diakses karena stack-frame dihancurkan. Dalam JavaScript, jika Anda mendeklarasikan suatu fungsi di dalam fungsi lain, maka variabel lokal dari fungsi luar tetap dapat diakses setelah kembali darinya. Dengan cara ini, dalam kode di atas,
secret
tetap tersedia untuk objek fungsiinner
, setelah kembali darifoo
.Penggunaan Penutupan
Penutupan berguna setiap kali Anda membutuhkan keadaan pribadi yang terkait dengan suatu fungsi. Ini adalah skenario yang sangat umum - dan ingat: JavaScript tidak memiliki sintaksis kelas hingga 2015, dan itu masih tidak memiliki sintaksis bidang pribadi. Penutupan memenuhi kebutuhan ini.
Variabel Instance Pribadi
Dalam kode berikut, fungsi
toString
menutup rincian mobil.Pemrograman Fungsional
Dalam kode berikut, fungsi
inner
ditutup atas keduanyafn
danargs
.Pemrograman Berorientasi Acara
Dalam kode berikut, fungsi
onClick
menutup variabelBACKGROUND_COLOR
.Modularisasi
Dalam contoh berikut, semua detail implementasi disembunyikan di dalam ekspresi fungsi yang segera dieksekusi. Fungsi
tick
dantoString
menutup negara swasta dan fungsi yang mereka butuhkan untuk menyelesaikan pekerjaan mereka. Penutupan memungkinkan kami melakukan modularisasi dan merangkum kode kami.Contohnya
Contoh 1
Contoh ini menunjukkan bahwa variabel lokal tidak disalin dalam penutupan: penutupan mempertahankan referensi ke variabel asli sendiri . Seolah-olah tumpukan-bingkai tetap hidup dalam memori bahkan setelah fungsi luar keluar.
Contoh 2
Dalam kode berikut, tiga metode
log
,increment
danupdate
semuanya menutup lingkungan leksikal yang sama.Dan setiap kali
createObject
dipanggil, konteks eksekusi baru (stack frame) dibuat dan variabel yang sama sekali barux
, dan serangkaian fungsi baru (log
dll.) Dibuat, yang menutup variabel baru ini.Contoh 3
Jika Anda menggunakan variabel yang dideklarasikan menggunakan
var
, berhati-hatilah Anda memahami variabel mana yang Anda tutupi. Variabel yang dideklarasikan menggunakanvar
diangkat. Ini jauh dari masalah dalam JavaScript modern karena pengenalanlet
danconst
.Dalam kode berikut, setiap kali di sekitar loop, fungsi baru
inner
dibuat, yang menutupi
. Tetapi karenavar i
diangkat di luar loop, semua fungsi dalam ini menutup variabel yang sama, yang berarti bahwa nilai akhiri
(3) dicetak, tiga kali.Poin terakhir:
function
dari dalam fungsi lain adalah contoh klasik dari penutupan, karena keadaan di dalam fungsi luar secara implisit tersedia untuk fungsi dalam yang dikembalikan, bahkan setelah fungsi luar menyelesaikan eksekusi.eval()
di dalam suatu fungsi, penutupan digunakan. Teks yang Andaeval
dapat referensi variabel lokal dari fungsi, dan dalam mode non-ketat Anda bahkan dapat membuat variabel lokal baru dengan menggunakaneval('var foo = …')
.new Function(…)
( Function constructor ) di dalam suatu fungsi, ia tidak menutup lingkungan leksikalnya: ia menutup konteks global sebagai gantinya. Fungsi baru tidak dapat merujuk variabel lokal dari fungsi luar.Tautan
sumber
Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created.
dari developer.mozilla.org/en-US/docs/Web/JavaScript/Closureslet i = 0
bukanvar i = 0
dalam Contoh 5, makatestList()
akan mencetak apa yang Anda inginkan pada awalnya.Setiap fungsi dalam JavaScript memelihara tautan ke lingkungan leksikal luarnya. Lingkungan leksikal adalah peta dari semua nama (mis. Variabel, parameter) dalam lingkup, dengan nilainya.
Jadi, setiap kali Anda melihat
function
kata kunci, kode di dalam fungsi itu memiliki akses ke variabel yang dinyatakan di luar fungsi.Ini akan masuk
16
karena fungsibar
menutup parameterx
dan variabeltmp
, yang keduanya ada di lingkungan leksikal dari fungsi luarfoo
.Fungsi
bar
, bersama dengan hubungannya dengan lingkungan fungsi leksikalfoo
adalah penutupan.Fungsi tidak harus kembali untuk membuat penutupan. Hanya berdasarkan deklarasi, setiap fungsi menutup lingkungan leksikal yang melingkupinya, membentuk penutupan.
Fungsi di atas juga akan mencatat 16, karena kode di dalamnya
bar
masih dapat merujuk ke argumenx
dan variabeltmp
, meskipun mereka tidak lagi secara langsung dalam cakupan.Namun, karena
tmp
masih berkeliaran di dalambar
penutupan, itu tersedia untuk ditambahkan. Itu akan bertambah setiap kali Anda meneleponbar
.Contoh paling sederhana dari penutupan adalah ini:
Ketika fungsi JavaScript dipanggil, konteks eksekusi baru
ec
dibuat. Bersama dengan argumen fungsi dan objek target, konteks eksekusi ini juga menerima tautan ke lingkungan leksikal dari konteks eksekusi pemanggilan, artinya variabel yang dideklarasikan di lingkungan leksikal luar (dalam contoh di atas, keduanyaa
danb
) tersedia dariec
.Setiap fungsi menciptakan penutupan karena setiap fungsi memiliki tautan ke lingkungan leksikal luarnya.
Perhatikan bahwa variabel itu sendiri terlihat dari dalam penutupan, bukan salinan.
sumber
delete
gagal. Namun demikian, lingkungan leksikal yang akan dibawa fungsi sebagai [[Cakupan]] (dan akhirnya digunakan sebagai basis untuk lingkungan leksikal itu sendiri ketika dipanggil) ditentukan ketika pernyataan yang mendefinisikan fungsi dieksekusi. Ini berarti bahwa fungsi yang menutup atas isi SELURUH lingkup mengeksekusi, terlepas dari nilai-nilai yang sebenarnya mengacu dan apakah itu lolos lingkup. Silakan lihat bagian 13.2 dan 10 di specKATA PENGANTAR: jawaban ini ditulis ketika pertanyaannya adalah:
Saya cukup yakin saya adalah satu-satunya orang yang mencoba untuk mengambil pertanyaan awal secara harfiah. Sejak itu, pertanyaannya bermutasi beberapa kali, jadi jawaban saya sekarang mungkin tampak sangat konyol & tidak pada tempatnya. Semoga ide umum cerita tetap menyenangkan bagi sebagian orang.
Saya penggemar analogi dan metafora ketika menjelaskan konsep-konsep yang sulit, jadi izinkan saya mencoba cerita saya.
Pada suatu ketika:
Ada seorang putri ...
Dia hidup di dunia yang indah penuh petualangan. Dia bertemu Pangeran Tampan, berkuda mengelilingi dunianya dengan naga unicorn, bertempur, bertemu binatang yang bisa bicara, dan banyak hal fantastik lainnya.
Tetapi dia harus selalu kembali ke dunia tugasnya yang membosankan dan orang dewasa.
Dan dia sering memberi tahu mereka tentang petualangan terbarunya yang menakjubkan sebagai seorang putri.
Tapi yang akan mereka lihat hanyalah seorang gadis kecil ...
... bercerita tentang sihir dan fantasi.
Dan meskipun orang dewasa tahu tentang putri asli, mereka tidak akan pernah percaya pada unicorn atau naga karena mereka tidak pernah bisa melihat mereka. Orang dewasa mengatakan bahwa mereka hanya ada di dalam imajinasi gadis kecil itu.
Tetapi kita tahu kebenaran yang sebenarnya; bahwa gadis kecil dengan putri di dalam ...
... benar-benar seorang putri dengan seorang gadis kecil di dalamnya.
sumber
story()
fungsi tersebut, yang merupakan satu-satunya antarmuka yanglittleGirl
terpapar contohnya ke dunia sihir.story
adalah penutupan tetapi jika kode sudahvar story = function() {}; return story;
makalittleGirl
akan menjadi penutupan. Setidaknya itulah kesan yang saya dapatkan dari penggunaan metode 'pribadi' MDN dengan penutupan : "Tiga fungsi publik itu adalah penutupan yang memiliki lingkungan yang sama."story
adalah penutup yang merujuk pada lingkungan yang disediakan dalam lingkupprincess
.princess
juga merupakan penutupan tersirat lainnya , yaituprincess
danlittleGirl
akan berbagi referensi keparents
array yang akan ada kembali di lingkungan / lingkup di manalittleGirl
ada danprincess
didefinisikan.princess
daripada apa yang tertulis. Sayangnya cerita ini sekarang agak tidak pada tempatnya di utas ini. Awalnya pertanyaannya adalah untuk "menjelaskan penutupan JavaScript ke yang berusia 5 tahun"; respons saya adalah satu-satunya yang bahkan berusaha melakukan itu. Saya tidak ragu bahwa itu akan gagal total, tetapi setidaknya respons ini mungkin memiliki kesempatan untuk mempertahankan minat anak berusia 5 tahun.Mengambil pertanyaan dengan serius, kita harus mencari tahu apa yang khas 6 tahun mampu secara kognitif, meskipun harus diakui, orang yang tertarik pada JavaScript tidak begitu khas.
Tentang Perkembangan Anak: 5 hingga 7 Tahun dikatakan:
Kita dapat menggunakan contoh ini untuk menjelaskan penutupan, sebagai berikut:
Kami dapat mengkodekan ini dalam JavaScript seperti ini:
Poin lebih lanjut yang menjelaskan mengapa penutupan menarik:
makeKitchen()
dipanggil, penutupan baru dibuat dengan tersendiritrashBags
.trashBags
variabel lokal ke dalam setiap dapur dan tidak dapat diakses di luar, tapi fungsi batin padagetTrashBag
properti tidak memiliki akses ke sana.getTrashBag
fungsi melakukan itu di sini.sumber
The Straw Man
Saya perlu tahu berapa kali sebuah tombol diklik dan melakukan sesuatu pada setiap klik ketiga ...
Solusi yang Cukup Jelas
Sekarang ini akan berhasil, tetapi ia merambah ke lingkup luar dengan menambahkan variabel, yang tujuan utamanya adalah untuk melacak jumlah. Dalam beberapa situasi, ini lebih disukai karena aplikasi luar Anda mungkin memerlukan akses ke informasi ini. Namun dalam kasus ini, kami hanya mengubah perilaku klik setiap ketiga, jadi lebih baik menyertakan fungsi ini di dalam pengendali event .
Pertimbangkan opsi ini
Perhatikan beberapa hal di sini.
Dalam contoh di atas, saya menggunakan perilaku penutupan JavaScript. Perilaku ini memungkinkan setiap fungsi memiliki akses ke ruang lingkup di mana ia dibuat, tanpa batas. Untuk menerapkannya secara praktis, saya segera menjalankan fungsi yang mengembalikan fungsi lain, dan karena fungsi yang saya kembalikan memiliki akses ke variabel jumlah internal (karena perilaku penutupan yang dijelaskan di atas) ini menghasilkan ruang lingkup pribadi untuk penggunaan oleh hasil fungsi ... Tidak begitu sederhana? Mari kita encerkan ...
Penutupan satu garis sederhana
Semua variabel di luar fungsi yang dikembalikan tersedia untuk fungsi yang dikembalikan, tetapi mereka tidak secara langsung tersedia untuk objek fungsi yang dikembalikan ...
Mendapatkan? Jadi, dalam contoh utama kami, variabel jumlah terdapat di dalam penutupan dan selalu tersedia untuk pengendali acara, sehingga mempertahankan statusnya dari klik ke klik.
Juga, keadaan variabel pribadi ini sepenuhnya dapat diakses, baik untuk pembacaan dan penugasan ke variabel cakupan pribadi.
Ini dia; Anda sekarang sepenuhnya merangkum perilaku ini.
Posting Blog Lengkap (termasuk pertimbangan jQuery)
sumber
Penutupan sulit dijelaskan karena mereka digunakan untuk membuat beberapa perilaku berfungsi yang diharapkan semua orang secara intuitif untuk bekerja. Saya menemukan cara terbaik untuk menjelaskannya (dan cara saya mempelajari apa yang mereka lakukan) adalah membayangkan situasi tanpa mereka:
Apa yang akan terjadi di sini jika JavaScript tidak mengetahui penutupan? Cukup ganti panggilan di baris terakhir dengan badan metodenya (yang pada dasarnya adalah fungsi yang dipanggil) dan Anda dapat:
Sekarang, di mana definisi
x
? Kami tidak mendefinisikannya dalam ruang lingkup saat ini. Satu-satunya solusi adalah dengan membiarkanplus5
membawa ruang lingkup (atau lebih tepatnya, ruang lingkup induknya) sekitar. Dengan cara ini,x
didefinisikan dengan baik dan terikat dengan nilai 5.sumber
TLDR
Penutupan adalah hubungan antara fungsi dan lingkungan leksikal luarnya (mis. Seperti yang ditulis), sehingga pengidentifikasi (variabel, parameter, deklarasi fungsi dll.) Yang didefinisikan dalam lingkungan tersebut dapat dilihat dari dalam fungsi, terlepas dari kapan atau dari di mana fungsi dipanggil.
Detail
Dalam terminologi spesifikasi ECMAScript, penutupan dapat dikatakan diimplementasikan oleh
[[Environment]]
referensi dari setiap fungsi-objek, yang menunjuk ke lingkungan leksikal di mana fungsi didefinisikan.Ketika suatu fungsi dipanggil melalui
[[Call]]
metode internal ,[[Environment]]
referensi pada objek-fungsi disalin ke referensi lingkungan luar dari catatan lingkungan dari konteks eksekusi yang baru dibuat (stack frame).Dalam contoh berikut, fungsi
f
menutup lingkungan leksikal dari konteks eksekusi global:Dalam contoh berikut, fungsi
h
menutup lingkungan leksikal fungsig
, yang, pada gilirannya, menutup lingkungan leksikal konteks eksekusi global.Jika fungsi dalam dikembalikan oleh luar, maka lingkungan leksikal luar akan bertahan setelah fungsi luar kembali. Ini karena lingkungan leksikal luar perlu tersedia jika fungsi dalam pada akhirnya dipanggil.
Dalam contoh berikut, fungsi
j
menutup lingkungan leksikal fungsii
, yang berarti bahwa variabelx
terlihat dari fungsi dalamj
, lama setelah fungsii
menyelesaikan eksekusi:Sebagai penutup, variabel-variabel di lingkungan leksikal luar itu sendiri tersedia, bukan salinan.
Rantai lingkungan leksikal, dihubungkan antara konteks eksekusi melalui referensi lingkungan luar, membentuk rantai lingkup dan mendefinisikan pengidentifikasi yang terlihat dari fungsi yang diberikan.
Harap perhatikan bahwa dalam upaya meningkatkan kejelasan dan akurasi, jawaban ini telah banyak berubah dari aslinya.
sumber
console.log
seperti itu. Jika orang lain tertarik, ada lebih banyak: developer.mozilla.org/en-US/docs/DOM/…var
).OK, kipas penutup berusia 6 tahun. Apakah Anda ingin mendengar contoh penutupan paling sederhana?
Mari kita bayangkan situasi selanjutnya: seorang pengemudi duduk di dalam mobil. Mobil itu ada di dalam pesawat. Pesawat ada di bandara. Kemampuan pengemudi untuk mengakses barang-barang di luar mobilnya, tetapi di dalam pesawat, bahkan jika pesawat itu meninggalkan bandara, adalah penutup. Itu dia. Saat Anda berusia 27 tahun, lihat penjelasan yang lebih terperinci atau pada contoh di bawah ini.
Inilah cara saya dapat mengubah cerita pesawat saya menjadi kode.
sumber
Ini adalah upaya untuk menghilangkan beberapa (mungkin) kesalahpahaman tentang penutupan yang muncul di beberapa jawaban lain.
sumber
Saya menulis posting blog sementara kembali menjelaskan penutupan. Inilah yang saya katakan tentang penutupan dalam hal mengapa Anda menginginkannya.
Dalam pengertian itu, mereka membiarkan fungsi bertindak sedikit seperti objek dengan atribut pribadi.
Pos lengkap:
Jadi apa penutupan ini?
sumber
devError = emailError("[email protected]", errorString)
dan kemudian memiliki versi kustom saya sendiri dari fungsi emailError bersama?Penutupan sederhana:
Contoh sederhana berikut mencakup semua poin utama penutupan JavaScript. *
Berikut adalah pabrik yang menghasilkan kalkulator yang dapat menambah dan mengalikan:
Poin utama: Setiap panggilan untuk
make_calculator
membuat variabel lokal barun
, yang terus dapat digunakan oleh kalkulator ituadd
danmultiply
fungsinya lama setelahmake_calculator
kembali.Jika Anda terbiasa dengan bingkai tumpukan, kalkulator ini tampak aneh: Bagaimana mereka dapat tetap mengakses
n
setelahmake_calculator
pengembalian? Jawabannya adalah membayangkan bahwa JavaScript tidak menggunakan "stack frames", tetapi sebaliknya menggunakan "heap frames", yang dapat bertahan setelah pemanggilan fungsi yang membuatnya kembali.Fungsi dalam suka
add
danmultiply
, yang mengakses variabel yang dinyatakan dalam fungsi luar ** , disebut closure .Cukup banyak untuk penutupan.
* Sebagai contoh, ini mencakup semua poin dalam artikel "Penutup untuk Dummies" yang diberikan dalam jawaban lain , kecuali contoh 6, yang hanya menunjukkan bahwa variabel dapat digunakan sebelum dideklarasikan, fakta yang bagus untuk diketahui tetapi sama sekali tidak terkait dengan penutupan. Ini juga mencakup semua poin dalam jawaban yang diterima , kecuali untuk poin (1) yang berfungsi menyalin argumen mereka ke dalam variabel lokal (argumen fungsi yang disebutkan), dan (2) bahwa menyalin angka membuat angka baru, tetapi menyalin referensi objek memberi Anda referensi lain ke objek yang sama. Ini juga baik untuk diketahui tetapi sekali lagi sama sekali tidak terkait dengan penutupan. Ini juga sangat mirip dengan contoh dalam jawaban ini tetapi sedikit lebih pendek dan kurang abstrak. Itu tidak mencakup titikjawaban ini atau komentar ini , yaitu JavaScript yang membuatnya sulit untuk menyambungkan arusnilai variabel loop ke fungsi dalam Anda: Langkah "memasukkan" hanya dapat dilakukan dengan fungsi pembantu yang membungkus fungsi batin Anda dan dipanggil pada setiap iterasi loop. (Sebenarnya, fungsi bagian dalam mengakses salinan fungsi helper dari variabel, alih-alih menyambungkan sesuatu.) Sekali lagi, sangat berguna saat membuat penutupan, tetapi bukan bagian dari apa penutupan itu atau bagaimana kerjanya. Ada kebingungan tambahan karena penutupan bekerja secara berbeda dalam bahasa fungsional seperti ML, di mana variabel terikat dengan nilai daripada ruang penyimpanan, memberikan aliran konstan orang-orang yang memahami penutupan dengan cara (yaitu cara "menghubungkan") yaitu hanya salah untuk JavaScript, di mana variabel selalu terikat ke ruang penyimpanan, dan tidak pernah ke nilai.
** Setiap fungsi luar, jika beberapa bersarang, atau bahkan dalam konteks global, karena jawaban ini menunjukkan dengan jelas.
sumber
first_calculator
merupakan objek (bukan fungsi) Anda tidak boleh menggunakan tanda kurungsecond_calculator = first_calculator;
, karena ini adalah tugas, bukan panggilan fungsi. Untuk menjawab pertanyaan Anda, maka hanya akan ada satu panggilan ke make_calculator, jadi hanya satu kalkulator yang dibuat, dan variabel first_calculator dan second_calculator keduanya akan merujuk ke kalkulator yang sama, sehingga jawabannya adalah 3, 403, 4433, 44330.Bagaimana saya menjelaskannya kepada anak berusia enam tahun:
Anda tahu bagaimana orang dewasa dapat memiliki rumah, dan mereka menyebutnya rumah? Ketika seorang ibu memiliki anak, anak itu tidak benar-benar memiliki apa pun, bukan? Tetapi orang tuanya memiliki rumah, jadi setiap kali seseorang bertanya kepada anak "Di mana rumahmu?", Dia dapat menjawab "rumah itu!", Dan menunjuk ke rumah orang tuanya. "Penutupan" adalah kemampuan anak untuk selalu (bahkan jika di luar negeri) dapat mengatakan bahwa ia memiliki rumah, meskipun sebenarnya orang tua yang memiliki rumah itu.
sumber
Bisakah Anda menjelaskan penutupan kepada anak berusia 5 tahun? *
Saya masih berpikir penjelasan Google bekerja dengan sangat baik dan singkat:
* Pertanyaan # AC
sumber
Saya cenderung belajar lebih baik dengan perbandingan BAIK / BURUK. Saya suka melihat kode yang bekerja diikuti oleh kode yang tidak bekerja yang mungkin ditemui seseorang. Saya mengumpulkan jsFiddle yang melakukan perbandingan dan mencoba meredakan perbedaan menjadi penjelasan paling sederhana yang dapat saya berikan .
Penutupan dilakukan dengan benar:
Dalam kode di atas
createClosure(n)
dipanggil dalam setiap iterasi dari loop. Perhatikan bahwa saya menamai variabeln
untuk menyorot bahwa itu adalah variabel baru yang dibuat dalam lingkup fungsi baru dan bukan variabel yang sama sepertiindex
yang terikat pada lingkup luar.Ini menciptakan ruang lingkup baru dan
n
terikat pada ruang lingkup itu; ini berarti kami memiliki 10 cakupan terpisah, satu untuk setiap iterasi.createClosure(n)
mengembalikan fungsi yang mengembalikan n dalam lingkup itu.Dalam setiap ruang lingkup
n
terikat dengan nilai apa pun yang dimilikinya saatcreateClosure(n)
dipanggil sehingga fungsi bersarang yang dikembalikan akan selalu mengembalikan nilain
yang dimilikinya saatcreateClosure(n)
dipanggil.Penutupan yang dilakukan salah:
Dalam kode di atas, loop telah dipindahkan dalam
createClosureArray()
fungsi dan fungsi sekarang hanya mengembalikan array yang sudah selesai, yang sekilas tampak lebih intuitif.Apa yang mungkin tidak jelas adalah bahwa karena
createClosureArray()
hanya dipanggil sekali hanya satu ruang lingkup yang dibuat untuk fungsi ini, bukan satu untuk setiap iterasi dari loop.Dalam fungsi ini variabel bernama
index
didefinisikan. Loop berjalan dan menambahkan fungsi ke array yang kembaliindex
. Catatan yangindex
didefinisikan dalamcreateClosureArray
fungsi yang hanya dipanggil sekali saja.Karena hanya ada satu ruang lingkup dalam
createClosureArray()
fungsi,index
hanya terikat pada nilai dalam ruang lingkup itu. Dengan kata lain, setiap kali loop mengubah nilaiindex
, itu mengubahnya untuk semua yang mereferensikannya dalam lingkup itu.Semua fungsi yang ditambahkan ke array mengembalikan
index
variabel SAMA dari lingkup induk di mana ia didefinisikan bukan 10 yang berbeda dari 10 cakupan yang berbeda seperti contoh pertama. Hasil akhirnya adalah bahwa semua 10 fungsi mengembalikan variabel yang sama dari cakupan yang sama.Setelah loop selesai dan
index
dilakukan modifikasi nilai akhir adalah 10, oleh karena itu setiap fungsi yang ditambahkan ke array mengembalikan nilaiindex
variabel tunggal yang sekarang diatur ke 10.Hasil
sumber
let
untukvar
memperbaiki perbedaan.n
dibuat di penutupan baru. Kami hanya mengembalikan suatu fungsi sehingga kami dapat menyimpannya di dalam array dan menjalankannya nanti.arr[index] = (function (n) { return 'n = ' + n; })(index);
. Tapi kemudian Anda menyimpan string yang dihasilkan dalam array daripada fungsi untuk memanggil yang mengalahkan titik contoh saya.Wikipedia pada penutupan :
Secara teknis, dalam JavaScript , setiap fungsi adalah penutupan . Itu selalu memiliki akses ke variabel yang didefinisikan dalam lingkup sekitarnya.
Karena konstruksi yang mendefinisikan ruang lingkup dalam JavaScript adalah fungsi , bukan blok kode seperti dalam banyak bahasa lain, apa yang biasanya kita maksud dengan penutupan dalam JavaScript adalah fungsi yang bekerja dengan variabel non-lokal yang didefinisikan dalam fungsi sekitarnya yang sudah dijalankan .
Penutupan sering digunakan untuk membuat fungsi dengan beberapa data pribadi yang tersembunyi (tetapi tidak selalu demikian).
ems
Contoh di atas menggunakan fungsi anonim, yang dieksekusi sekali. Tetapi tidak harus demikian. Itu bisa dinamai (misalnya
mkdb
) dan dieksekusi nanti, menghasilkan fungsi basis data setiap kali dipanggil. Setiap fungsi yang dihasilkan akan memiliki objek basis data tersembunyi sendiri. Contoh penggunaan lain dari penutupan adalah ketika kita tidak mengembalikan fungsi, tetapi objek yang berisi beberapa fungsi untuk tujuan yang berbeda, masing-masing fungsi tersebut memiliki akses ke data yang sama.sumber
Saya menyusun tutorial JavaScript interaktif untuk menjelaskan cara kerja penutupan. Apa itu Penutupan?
Inilah salah satu contohnya:
sumber
Rahasia untuk fungsi JavaScript adalah variabel pribadi
Setiap kali Anda menyebutnya, "nama" variabel lokal dibuat dan diberi nama "Mary". Dan setiap kali fungsi keluar, variabelnya hilang dan namanya dilupakan.
Seperti yang Anda tebak, karena variabel dibuat kembali setiap kali fungsi dipanggil, dan tidak ada orang lain yang akan mengetahuinya, pasti ada tempat rahasia tempat mereka disimpan. Itu bisa disebut Kamar Rahasia atau tumpukan atau ruang lingkup lokal tetapi tidak terlalu penting. Kita tahu mereka ada di sana, di suatu tempat, tersembunyi di dalam ingatan.
Tetapi, dalam JavaScript ada hal yang sangat istimewa ini, fungsi-fungsi yang dibuat di dalam fungsi-fungsi lain, juga dapat mengetahui variabel lokal orang tua mereka dan menjaganya selama mereka masih hidup.
Jadi, selama kita berada di fungsi orangtua, ia dapat membuat satu atau lebih fungsi anak yang berbagi variabel rahasia dari tempat rahasia.
Tetapi yang menyedihkan adalah, jika anak itu juga merupakan variabel pribadi dari fungsi orang tuanya, ia juga akan mati ketika orang tua berakhir, dan rahasia akan mati bersama mereka.
Jadi untuk hidup, anak harus pergi sebelum terlambat
Dan sekarang, meskipun Mary "tidak lagi berlari", ingatannya tidak hilang dan anaknya akan selalu mengingat namanya dan rahasia lain yang mereka bagi selama mereka bersama.
Jadi, jika Anda memanggil anak "Alice", dia akan merespons
Hanya itu yang bisa diceritakan.
sumber
Saya tidak mengerti mengapa jawabannya sangat rumit di sini.
Berikut ini adalah penutupan:
Iya. Anda mungkin menggunakannya beberapa kali sehari.
sumber
a
. Menurut saya, yang mengejutkan adalah bahwa objek lingkup JS secara efektif menyediakana
properti daripada konstanta. Dan Anda hanya akan melihat perilaku penting itu jika Anda memodifikasinya, seperti dalamreturn a++;
Contoh untuk titik pertama oleh dlaliberte:
sumber
Penutupan adalah tempat fungsi dalam memiliki akses ke variabel di fungsi luarnya. Itu mungkin penjelasan satu baris paling sederhana yang bisa Anda dapatkan untuk penutupan.
sumber
Saya tahu sudah ada banyak solusi, tetapi saya kira skrip kecil dan sederhana ini dapat berguna untuk menunjukkan konsep:
sumber
Anda sedang tidur dan Anda mengundang Dan. Anda memberi tahu Dan untuk membawa satu XBox controller.
Dan mengundang Paul. Dan meminta Paul untuk membawa satu controller. Berapa banyak pengendali yang dibawa ke pesta?
sumber
Penulis Closures telah menjelaskan penutupan dengan cukup baik, menjelaskan alasan mengapa kami membutuhkannya dan juga menjelaskan LexicalEnvironment yang diperlukan untuk memahami penutupan.
Berikut ringkasannya:
Bagaimana jika suatu variabel diakses, tetapi itu bukan lokal? Seperti di sini:
Dalam hal ini, interpreter menemukan variabel di
LexicalEnvironment
objek luar .Proses ini terdiri dari dua langkah:
Ketika suatu fungsi dibuat, ia akan mendapatkan properti tersembunyi, bernama [[Cakupan]], yang mereferensikan LexicalEnvironment saat ini.
Jika variabel dibaca, tetapi tidak dapat ditemukan di mana pun, kesalahan dihasilkan.
Fungsi bersarang
Fungsi dapat bersarang di dalam satu sama lain, membentuk rantai Lingkungan Lexical yang juga dapat disebut rantai lingkup.
Jadi, fungsi g memiliki akses ke g, a dan f.
Penutupan
Fungsi bersarang dapat terus hidup setelah fungsi luar selesai:
Menandai Lingkungan Lexical:
Seperti yang kita lihat,
this.say
adalah properti di objek pengguna, jadi itu terus hidup setelah Pengguna selesai.Dan jika Anda ingat, ketika
this.say
dibuat, itu (karena setiap fungsi) mendapatkan referensi internalthis.say.[[Scope]]
ke LexicalEnvironment saat ini. Jadi, Lingkungan Lexical dari eksekusi Pengguna saat ini tetap dalam memori. Semua variabel Pengguna juga adalah propertinya, sehingga mereka juga dijaga dengan hati-hati, tidak dibuang seperti biasanya.Intinya adalah untuk memastikan bahwa jika fungsi dalam ingin mengakses variabel luar di masa depan, ia dapat melakukannya.
Untuk meringkas:
Ini disebut penutupan.
sumber
Fungsi JavaScript dapat mengakses:
Jika suatu fungsi mengakses lingkungannya, maka fungsinya adalah penutupan.
Perhatikan bahwa fungsi luar tidak diperlukan, meskipun mereka menawarkan manfaat yang tidak saya bahas di sini. Dengan mengakses data di lingkungannya, penutupan membuat data tetap hidup. Dalam subkap fungsi luar / dalam, fungsi luar dapat membuat data lokal dan akhirnya keluar, namun, jika ada fungsi dalam yang bertahan setelah fungsi luar keluar, maka fungsi dalam menyimpan data lokal fungsi luar hidup.
Contoh penutupan yang menggunakan lingkungan global:
Bayangkan bahwa peristiwa tombol Stack Overflow Vote-Up dan Vote-Down diimplementasikan sebagai penutupan, voteUp_click dan voteDown_click, yang memiliki akses ke variabel eksternal adalah VotedUp dan isVotedDown, yang didefinisikan secara global. (Demi kesederhanaan, saya mengacu pada tombol Vote Pertanyaan StackOverflow, bukan array tombol Jawab Vote.)
Ketika pengguna mengklik tombol VoteUp, fungsi voteUp_click memeriksa apakah isVotedDown == benar untuk menentukan apakah akan memilih atau hanya membatalkan suara turun. Function voteUp_click adalah penutup karena mengakses lingkungannya.
Keempat fungsi ini adalah penutupan karena mereka semua mengakses lingkungan mereka.
sumber
Sebagai ayah dari seorang anak berusia 6 tahun, yang saat ini mengajar anak-anak kecil (dan seorang pemula yang relatif berkode tanpa pendidikan formal sehingga koreksi akan diperlukan), saya pikir pelajaran akan tetap terbaik melalui permainan langsung. Jika anak 6 tahun siap untuk memahami apa penutupan itu, maka mereka cukup tua untuk pergi sendiri. Saya sarankan menempelkan kode ke jsfiddle.net, menjelaskan sedikit, dan meninggalkan mereka sendiri untuk membuat lagu yang unik. Teks penjelasan di bawah ini mungkin lebih cocok untuk anak berusia 10 tahun.
INSTRUKSI
DATA: Data adalah kumpulan fakta. Ini bisa berupa angka, kata, ukuran, pengamatan atau bahkan hanya deskripsi benda. Anda tidak bisa menyentuhnya, menciumnya, atau merasakannya. Anda dapat menuliskannya, berbicara dan mendengarnya. Anda bisa menggunakannya untuk membuat aroma dan rasa sentuh menggunakan komputer. Ini dapat dimanfaatkan oleh komputer menggunakan kode.
KODE: Semua tulisan di atas disebut kode . Itu ditulis dalam JavaScript.
JAVASCRIPT: JavaScript adalah bahasa. Seperti Bahasa Inggris atau Bahasa Prancis atau Bahasa Mandarin adalah bahasa. Ada banyak bahasa yang dimengerti oleh komputer dan prosesor elektronik lainnya. Agar JavaScript dipahami oleh komputer, ia membutuhkan juru bahasa. Bayangkan jika seorang guru yang hanya berbicara bahasa Rusia datang untuk mengajar kelas Anda di sekolah. Ketika guru mengatakan "все садятся", kelas tidak akan mengerti. Tapi untungnya Anda memiliki murid Rusia di kelas Anda yang memberi tahu semua orang bahwa ini berarti "semua orang duduk" - jadi Anda semua melakukannya. Kelasnya seperti komputer dan murid Rusia adalah penerjemahnya. Untuk JavaScript, juru bahasa yang paling umum disebut browser.
BROWSER: Ketika Anda terhubung ke Internet di komputer, tablet atau telepon untuk mengunjungi situs web, Anda menggunakan browser. Contoh yang mungkin Anda ketahui adalah Internet Explorer, Chrome, Firefox, dan Safari. Browser dapat memahami JavaScript dan memberi tahu komputer apa yang perlu dilakukan. Instruksi JavaScript disebut fungsi.
FUNGSI: Fungsi dalam JavaScript seperti pabrik. Mungkin pabrik kecil dengan hanya satu mesin di dalamnya. Atau mungkin mengandung banyak pabrik kecil lainnya, masing-masing dengan banyak mesin melakukan pekerjaan yang berbeda. Di pabrik pakaian kehidupan nyata Anda mungkin memiliki rim kain dan kumparan benang masuk dan T-shirt dan celana jeans keluar. Pabrik JavaScript kami hanya memproses data, tidak dapat menjahit, mengebor lubang, atau melelehkan logam. Di pabrik JavaScript kami data masuk dan data keluar.
Semua data ini kedengarannya agak membosankan, tetapi sangat keren; kita mungkin memiliki fungsi yang memberi tahu robot apa yang harus dibuat untuk makan malam. Katakanlah saya mengundang Anda dan teman Anda ke rumah saya. Anda suka kaki ayam terbaik, saya suka sosis, teman Anda selalu menginginkan apa yang Anda inginkan dan teman saya tidak makan daging.
Saya tidak punya waktu untuk berbelanja, jadi fungsi perlu tahu apa yang kita miliki di lemari es untuk membuat keputusan. Setiap bahan memiliki waktu memasak yang berbeda dan kami ingin semuanya disajikan panas oleh robot secara bersamaan. Kita perlu menyediakan fungsi dengan data tentang apa yang kita sukai, fungsinya bisa 'berbicara' ke lemari es, dan fungsi itu bisa mengendalikan robot.
Suatu fungsi biasanya memiliki nama, tanda kurung dan kurung kurawal. Seperti ini:
Perhatikan itu
/*...*/
dan//
hentikan kode yang sedang dibaca oleh browser.NAME: Anda dapat memanggil fungsi apa saja kata yang Anda inginkan. Contoh "cookMeal" adalah tipikal dalam menggabungkan dua kata bersama dan memberikan yang kedua huruf kapital di awal - tetapi ini tidak perlu. Itu tidak dapat memiliki ruang di dalamnya, dan itu tidak bisa menjadi nomor sendiri.
PARENTES: "Kurung" atau
()
kotak surat di pintu fungsi pabrik JavaScript atau kotak pos di jalan untuk mengirim paket informasi ke pabrik. Terkadang kotak pos mungkin ditandai misalnyacookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime)
, dalam hal ini Anda tahu data apa yang harus Anda berikan.BRACES: "Kawat gigi" yang terlihat seperti ini
{}
adalah jendela berwarna dari pabrik kami. Dari dalam pabrik Anda bisa melihat keluar, tetapi dari luar Anda tidak bisa melihatnya.CONTOH KODE PANJANG DI ATAS
Kode kita dimulai dengan fungsi kata , jadi kita tahu itu salah! Kemudian nama fungsi tersebut dinyanyikan - itulah deskripsi saya sendiri tentang fungsi tersebut. Kemudian tanda kurung () . Tanda kurung selalu ada untuk suatu fungsi. Kadang-kadang mereka kosong, dan kadang-kadang mereka memiliki sesuatu dalam satu ini memiliki sebuah kata dalam.:
(person)
. Setelah ini ada penjepit seperti ini{
. Ini menandai awal dari fungsi sing () . Ini memiliki pasangan yang menandai akhir dari bernyanyi () seperti ini}
Jadi fungsi ini mungkin ada hubungannya dengan bernyanyi, dan mungkin perlu beberapa data tentang seseorang. Di dalamnya ada instruksi untuk melakukan sesuatu dengan data itu.
Sekarang, setelah fungsi bernyanyi () , di dekat akhir kode adalah garis
VARIABEL: Huruf var berarti "variabel". Variabel seperti amplop. Di luar amplop ini ditandai "orang". Di bagian dalamnya berisi selembar kertas dengan informasi yang dibutuhkan fungsi kita, beberapa huruf dan spasi bergabung bersama seperti seutas tali (disebut string) yang membuat frasa membaca "seorang wanita tua". Amplop kami dapat berisi hal-hal lain seperti angka (disebut bilangan bulat), instruksi (disebut fungsi), daftar (disebut array ). Karena variabel ini ditulis di luar semua kurung kurawal
{}
, dan karena Anda dapat melihat melalui jendela yang berwarna saat Anda berada di dalam kurung kurawal, variabel ini dapat dilihat dari mana saja dalam kode. Kami menyebutnya 'variabel global'.VARIABEL GLOBAL: seseorang adalah variabel global, yang berarti bahwa jika Anda mengubah nilainya dari "seorang wanita tua" menjadi "seorang pria muda", orang itu akan tetap menjadi seorang pria muda sampai Anda memutuskan untuk mengubahnya lagi dan bahwa fungsi lain di kode dapat melihat bahwa itu adalah seorang pria muda. Tekan F12tombol atau lihat pengaturan Opsi untuk membuka konsol pengembang browser dan ketik "orang" untuk melihat apa nilai ini. Ketik
person="a young man"
untuk mengubahnya dan kemudian ketik "orang" lagi untuk melihat bahwa itu telah berubah.Setelah ini, kita memiliki garis
Baris ini memanggil fungsi, seolah-olah memanggil anjing
Ketika browser telah memuat kode JavaScript dan mencapai garis ini, itu akan memulai fungsinya. Saya meletakkan baris di bagian akhir untuk memastikan bahwa browser memiliki semua informasi yang diperlukan untuk menjalankannya.
Fungsi mendefinisikan tindakan - fungsi utama adalah tentang bernyanyi. Ini berisi variabel yang disebut firstPart yang berlaku untuk bernyanyi tentang orang yang berlaku untuk masing-masing ayat dari lagu: "Ada" + orang + "yang menelan". Jika Anda mengetik firstPart ke konsol, Anda tidak akan mendapatkan jawaban karena variabel dikunci dalam suatu fungsi - browser tidak dapat melihat di dalam jendela berwarna kawat gigi.
PENUTUP: Penutupan adalah fungsi yang lebih kecil yang ada di dalam fungsi sing besar () . Pabrik kecil di dalam pabrik besar. Mereka masing-masing memiliki kawat gigi sendiri yang berarti bahwa variabel di dalamnya tidak dapat dilihat dari luar. Itu sebabnya nama variabel ( makhluk dan hasil ) dapat diulang dalam penutupan tetapi dengan nilai yang berbeda. Jika Anda mengetik nama-nama variabel ini di jendela konsol, Anda tidak akan mendapatkan nilainya karena disembunyikan oleh dua lapisan jendela berwarna.
Penutupan semua tahu apa variabel fungsi sing () dipanggil firstPart , karena mereka bisa melihat keluar dari jendela berwarna mereka.
Setelah penutupan datang garis
Fungsi sing () akan memanggil masing-masing fungsi ini sesuai urutan yang diberikan. Maka pekerjaan fungsi sing () akan dilakukan.
sumber
Oke, berbicara dengan anak berusia 6 tahun, saya mungkin akan menggunakan asosiasi berikut.
Bandingkan dengan situasi ketika pintu dikunci oleh angin dan tidak ada orang di dalam (pelaksanaan fungsi umum), dan kemudian beberapa kebakaran lokal terjadi dan membakar ruangan (pengumpul sampah: D), dan kemudian sebuah ruangan baru dibangun dan sekarang Anda dapat meninggalkan mainan lain di sana (contoh fungsi baru), tetapi tidak pernah mendapatkan mainan yang sama yang tersisa di contoh ruang pertama.
Untuk anak yang sudah lanjut, saya akan menempatkan sesuatu seperti yang berikut ini. Ini tidak sempurna, tetapi membuat Anda merasa tentang apa itu:
Seperti yang Anda lihat, mainan yang tersisa di kamar masih dapat diakses melalui saudara dan tidak masalah jika ruangan itu terkunci. Ini adalah jsbin untuk bermain-main dengannya.
sumber
Jawaban untuk anak berusia enam tahun (dengan asumsi dia tahu apa fungsi itu dan apa variabelnya, dan apa datanya):
Fungsi dapat mengembalikan data. Satu jenis data yang dapat Anda kembalikan dari suatu fungsi adalah fungsi lainnya. Ketika fungsi baru itu dikembalikan, semua variabel dan argumen yang digunakan dalam fungsi yang membuatnya tidak hilang. Sebaliknya, fungsi induk itu "ditutup." Dengan kata lain, tidak ada yang bisa melihat ke dalamnya dan melihat variabel yang digunakan kecuali untuk fungsi yang dikembalikan. Fungsi baru itu memiliki kemampuan khusus untuk melihat kembali ke dalam fungsi yang membuatnya dan melihat data di dalamnya.
Cara lain yang sangat sederhana untuk menjelaskannya adalah dalam hal ruang lingkup:
Setiap kali Anda membuat ruang lingkup yang lebih kecil di dalam ruang lingkup yang lebih besar, ruang lingkup yang lebih kecil akan selalu dapat melihat apa yang ada di ruang lingkup yang lebih besar.
sumber
Fungsi dalam JavaScript bukan hanya referensi ke sekumpulan instruksi (seperti dalam bahasa C), tetapi juga mencakup struktur data tersembunyi yang terdiri dari referensi untuk semua variabel nonlokal yang digunakannya (variabel yang ditangkap). Fungsi dua bagian seperti itu disebut penutupan. Setiap fungsi dalam JavaScript dapat dianggap sebagai penutupan.
Penutupan adalah fungsi dengan status. Ini agak mirip dengan "ini" dalam arti bahwa "ini" juga menyediakan status untuk fungsi tetapi fungsi dan "ini" adalah objek yang terpisah ("ini" hanyalah parameter mewah, dan satu-satunya cara untuk mengikatnya secara permanen ke fungsi adalah untuk membuat penutupan). Sementara "ini" dan fungsi selalu hidup secara terpisah, suatu fungsi tidak dapat dipisahkan dari penutupannya dan bahasa tidak menyediakan sarana untuk mengakses variabel yang ditangkap.
Karena semua variabel eksternal yang dirujuk oleh fungsi bersarang leksikal sebenarnya adalah variabel lokal dalam rantai fungsi leksikal yang melingkupinya (variabel global dapat diasumsikan sebagai variabel lokal dari beberapa fungsi root), dan setiap eksekusi tunggal dari suatu fungsi menciptakan instance baru dari variabel lokalnya, ini mengikuti bahwa setiap eksekusi fungsi yang mengembalikan (atau mentransfernya, seperti mendaftarkannya sebagai panggilan balik) fungsi bersarang menciptakan penutupan baru (dengan serangkaian variabel nonlokal yang direferensikan dan berpotensi unik yang mewakili pelaksanaannya konteks).
Juga, harus dipahami bahwa variabel lokal dalam JavaScript dibuat bukan pada frame stack, tetapi pada heap dan dihancurkan hanya ketika tidak ada yang mereferensikannya. Ketika suatu fungsi kembali, referensi ke variabel lokalnya dikurangi, tetapi mereka bisa tetap non-nol jika selama eksekusi saat ini mereka menjadi bagian dari penutupan dan masih direferensikan oleh fungsi bersarang secara leksikal (yang dapat terjadi hanya jika referensi ke fungsi bersarang ini dikembalikan atau sebaliknya ditransfer ke beberapa kode eksternal).
Sebuah contoh:
sumber
Mungkin sedikit melebihi segalanya kecuali yang paling dewasa sebelum berumur enam tahun, tetapi beberapa contoh yang membantu membuat konsep penutupan dalam JavaScript klik untuk saya.
Penutupan adalah fungsi yang memiliki akses ke ruang lingkup fungsi lain (variabel dan fungsinya). Cara termudah untuk membuat penutupan adalah dengan fungsi dalam suatu fungsi; alasannya adalah bahwa dalam JavaScript suatu fungsi selalu memiliki akses ke ruang lingkup fungsi yang mengandungnya.
PERINGATAN: monyet
Dalam contoh di atas, fungsi luar disebut yang pada gilirannya memanggil fungsi internal. Perhatikan bagaimana outerVar tersedia untuk fungsi dalam, dibuktikan dengan itu dengan benar memperingatkan nilai outerVar.
Sekarang pertimbangkan hal berikut:
PERINGATAN: monyet
referenceToInnerFunction diatur ke outerFunction (), yang hanya mengembalikan referensi ke innerFunction. Ketika referenceToInnerFunction dipanggil, ia mengembalikan outerVar. Sekali lagi, seperti di atas, ini menunjukkan bahwa fungsi dalam memiliki akses ke outerVar, variabel fungsi luar. Selain itu, menarik untuk dicatat bahwa ia mempertahankan akses ini bahkan setelah fungsi luar selesai dijalankan.
Dan di sinilah segalanya menjadi sangat menarik. Jika kami menyingkirkan outerFunction, katakan setel ke null, Anda mungkin berpikir bahwa referenceToInnerFunction akan kehilangan aksesnya ke nilai outerVar. Tapi ini bukan masalahnya.
ALERT: monyet ALERT: monyet
Tapi bagaimana bisa begitu? Bagaimana referenceToInnerFunction masih dapat mengetahui nilai outerVar sekarang bahwa outerFunction telah disetel ke nol?
Alasan bahwa referenceToInnerFunction masih dapat mengakses nilai outerVar adalah karena ketika penutupan pertama kali dibuat dengan menempatkan innerFunction di dalam outerFunction, innerFunction menambahkan referensi ke ruang lingkup outerFunction (variabel dan fungsinya) ke rantai cakupannya. Apa artinya ini adalah innerFunction memiliki pointer atau referensi ke semua variabel outerFunction, termasuk outerVar. Jadi, bahkan ketika outerFunction telah selesai dieksekusi, atau bahkan jika itu dihapus atau diatur ke nol, variabel-variabel dalam ruang lingkupnya, seperti outerVar, tetap ada di memori karena referensi yang luar biasa kepada mereka di bagian fungsi dalam yang telah dikembalikan ke referenceToInnerFunction. Untuk benar-benar melepaskan outerVar dan variabel luar OuterFunction dari memori Anda harus menyingkirkan referensi luar biasa ini kepada mereka,
//////////
Dua hal lain tentang penutupan harus diperhatikan. Pertama, penutupan akan selalu memiliki akses ke nilai terakhir dari fungsi yang mengandungnya.
PERINGATAN: gorila
Kedua, ketika sebuah penutupan dibuat, ia mempertahankan referensi ke semua variabel dan fungsi fungsi yang melampirkannya; tidak bisa memilih. Dan dengan demikian, penutupan harus digunakan dengan hemat, atau setidaknya dengan hati-hati, karena mereka bisa intensif memori; banyak variabel dapat disimpan dalam memori lama setelah fungsi yang mengandung selesai dieksekusi.
sumber
Saya cukup mengarahkan mereka ke halaman Mozilla Closures . Ini adalah penjelasan terbaik, paling ringkas dan sederhana tentang dasar-dasar penutupan dan penggunaan praktis yang saya temukan. Sangat disarankan bagi siapa pun yang belajar JavaScript.
Dan ya, saya bahkan merekomendasikannya kepada anak berusia 6 tahun - jika anak berusia 6 tahun itu belajar tentang penutupan, maka logis mereka siap untuk memahami penjelasan singkat dan sederhana yang disediakan dalam artikel.
sumber