Bayangin kamu pinjem buku dari perpus, terus pas keluar bawa juga catatan kecil yang kamu tulis selama baca di sana. Walaupun perpus udah tutup (function luar selesai), kamu tetep bisa baca catatannya — karena udah ada di kantong kamu. Itu Closure di JavaScript: function dalam "kantongin" variabel dari scope luar, tetep bisa pake walaupun scope itu udah lama selesai. Konsep yang bikin pemula bingung tapi powerful banget — fondasi dari banyak pattern modern: counter privat, factory function, module pattern.
💡 Closure di mana-mana. Setiap kali kamu pakai callback yang akses variabel dari luar fungsi callback-nya, kamu lagi pakai closure. React hooks (
useState,useEffect) dasarnya closure. Event handler dengan akses state? Closure. Paham closure = paham 60% pattern JavaScript modern.
function buatSapa(salam) {
return function(nama) {
return salam + ", " + nama + "!";
};
}
const sapaIndo = buatSapa("Halo");
sapaIndo("Budi"); // "Halo, Budi!"
sapaIndo("Ani"); // "Halo, Ani!"
sapaIndo tetap mengingat nilai salam meskipun buatSapa sudah selesai.
salam selama inner function masih ada referensi.Kegunaan closure:
- Data privacy — menyembunyikan variabel dari luar
- Factory functions — membuat fungsi yang dikustomisasi
- Counter/state — menyimpan state tanpa variabel global
function counter() {
let count = 0;
return {
tambah: () => ++count,
nilai: () => count
};
}
const c = counter();
c.tambah(); // 1
c.tambah(); // 2
c.nilai(); // 2
// count tidak bisa diakses langsung dari luar!
🎭 Analogi sehari-hari
Pernah pinjem buku dari perpus terus pas keluar bawa juga catatan kecil yang kamu tulis selama baca? Walaupun perpusnya udah tutup (function luar selesai), kamu tetap bisa baca catatannya — karena udah kamu kantongin. Itu closure: function dalem "kantongin" variabel dari scope luar, dan tetap bisa pakai walaupun scope itu udah lama bubar.
Counter pattern itu kayak celengan ayam jago — kamu cuma bisa masukin koin (tambah()) atau ngintip nominalnya lewat method (nilai()). Dari luar gak ada yang bisa langsung buka isi celengan, dilindungi cangkangnya. Encapsulation tanpa harus pake class — privasi data ala JavaScript jaman dulu yang masih relevan banget sampai sekarang.
⚠️ Jebakan yang sering ditemui:
- Loop dengan
var+ closure — semua callback baca variabel loop yang sama (variable bocor).for (var i = 0; i < 3; i++) setTimeout(() => log(i))print3, 3, 3. Pakailet→ print0, 1, 2.- Memory leak via closure — closure menahan seluruh scope, bukan cuma var yang dipakai. DOM element + closure besar = leak. Set
nullsaat tidak dipakai.- Stale closure — di React, callback yang di-define dalam useEffect "freeze" var saat itu. Pakai ref atau function setState
(prev) => ....- Shared state bug — multiple closure share variabel yang sama, terus mutate. Bug subtle. Pakai
const+ struktur baru.thisdi closure — closure mewarisithisdari scope luar (kalau arrow). Kalau function biasa,thisbaru per pemanggilan.
🧪 Tebakan cepat — closure bug klasik. Tanpa run kode, tebak output:
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); }Jawaban:
3, 3, 3. Bukan0, 1, 2. Karenavarshared scope di seluruh loop, semua callback bacaiyang sama (nilai akhir = 3). Fix: gantivarkelet— tiap iterasiletbikin block scope baru, callback masing-masing nyimpen snapshotiwaktu itu. Output jadi0, 1, 2. Bug klasik yang ngajarin kamu kenapavarditinggalin.
TL;DR: Closure = function yang "kantongin" variabel dari scope luar, tetep akses walau scope luar udah selesai. Fondasi banyak pattern modern: counter privat, factory function, React hooks (useState/useEffect dasarnya closure). Setiap callback yang akses variabel dari fungsi pembungkusnya = closure.