Fungsi di JavaScript boleh dibuat di dalam fungsi lain. Fungsi dalam itu tetap ingat variabel di sekitarnya, bahkan setelah fungsi luarnya selesai jalan. Dengan cara ini kamu bisa bikin penghitung, pabrik fungsi, dan data yang gak bisa diubah dari luar.
🧪 Tebakan cepat:
adanbdibuat dari fungsi yang sama. Kalauadinaikkan dua kali,bikut jadi 2 atau tetap 0? Tebak dulu, jawabannya ada di bagian "Fungsi yang ingat variabelnya".
Fungsi yang ingat variabelnya
function makeCounter() {
let count = 0;
return {
inc: () => ++count,
peek: () => count,
};
}
const a = makeCounter();
const b = makeCounter();
a.inc();
a.inc();
console.log(a.peek()); // 2
console.log(b.peek()); // 0
console.log(a.count); // undefined
let count = 0adalah variabel di dalammakeCounter.makeCountermengembalikan object berisi dua fungsi kecil.incmenjalankan++count: naikkancountsatu, lalu kembalikan nilai barunya (panggilan pertama 1, kedua 2).peekcuma membacacount.makeCounter()sudah selesai jalan, tapiincdanpeekmasih bisa memakaicount.- Tiap panggilan
makeCounter()bikincountbaru.adanbpunya hitungan masing-masing, jadibtetap 0. a.counthasilnyaundefined.countgak bisa dibaca dari luar, cuma lewatincdanpeek.
Daerah tempat sebuah variabel bisa dipakai disebut scope. Fungsi yang tetap ingat scope luarnya, tempat dia dibuat, namanya closure. Patokannya: fungsi ingat variabel di sekitar tempat dia ditulis, dan tiap kali fungsi luarnya dipanggil, variabel itu dibuat baru.
Fungsi yang mengembalikan fungsi
function buatSapa(salam) {
return function (nama) {
return salam + ", " + nama + "!";
};
}
const sapaPagi = buatSapa("Selamat pagi");
const sapaMalam = buatSapa("Selamat malam");
console.log(sapaPagi("Budi")); // Selamat pagi, Budi!
console.log(sapaMalam("Ani")); // Selamat malam, Ani!
console.log(buatSapa("Halo")("Rina")); // Halo, Rina!
buatSapagak mengembalikan teks, tapi sebuah fungsi.sapaPagiadalah fungsi itu, siap dipanggil nanti.- Fungsi dalamnya ingat
salamdari panggilan yang membuatnya, jadisapaPagidansapaMalammasing-masing punyasalamsendiri. buatSapa("Halo")("Rina"): kurung pertama bikin fungsinya, kurung kedua langsung memanggilnya.
Method yang berbagi satu variabel
function buatKeranjang() {
const isi = [];
return {
masukkan(barang) {
isi.push(barang);
},
jumlah() {
return isi.length;
},
};
}
const k = buatKeranjang();
k.masukkan("buku");
k.masukkan("pensil");
console.log(k.jumlah()); // 2
console.log(k.isi); // undefined
masukkan(barang) { ... }adalah cara singkat menulis method di dalam object.- Dua method itu dibuat di dalam
buatKeranjang, jadi dua-duanya memakaiisiyang sama. - Dari luar,
k.isigak ada, jadi keranjangnya cuma bisa diubah lewatmasukkan. Kalauisidisimpan sebagai properti object, siapa pun bisa menimpanya.
⚠️ Jebakan yang sering ketemu
- Variabel ditaruh di luar fungsi pembuatnya. Semua fungsi hasilnya jadi berbagi satu variabel, dan yang dibuat terakhir menimpa yang lain. Pakai parameter atau
letdi dalam fungsi pembuatnya. - Lupa
returnfungsi dalamnya.buatSapa("Halo")jadiundefined, danbuatSapa("Halo")("Rina")error karenaundefinedgak bisa dipanggil. =padahal maksudnya+=.total = ncuma menyimpan angka terakhir.total += nmenumpuk.
🔬 Coba sendiri
Alat di bawah berisi pola closure lain, dari penghitung privat sampai bug loop klasik. Pilih satu, lalu lihat variabel apa yang diingat closure-nya.
TL;DR: Closure adalah fungsi yang tetap ingat variabel dari scope tempat dia dibuat, walaupun fungsi luarnya sudah selesai jalan. Tiap panggilan fungsi luar bikin variabel baru, jadi makeCounter() dua kali menghasilkan dua hitungan terpisah. Pakai ini buat fungsi yang mengembalikan fungsi (buatSapa("Halo")("Rina")) dan buat data yang cuma bisa diubah lewat method-nya sendiri.