Deo zbornika Napredni Javaskript
Zatvorenost (closure)
Zatvorenost (closure) se stvara kada unutrašnja funkcija zadrži vezu sa opsegom važenja spoljašnje funkcije, i nakon što spoljašnja vrati svoj rezultat.
Opseg važenja funkcije se uglavnom uništava nakon što se funkcija izvrši, osim ako se desi nešto što će ga održati. Zatvorenost je blisko povezana sa opsegom važenja i funkcijama koje vraćaju funkcije u Javascriptu.
Primer: Brojač
// spoljasnja funkcija inicijalizuje brojac i vraca unutrasnju funkciju
function spoljasnja() {
let brojac = 1
return function() {
return brojac++
}
}
// konstanti je dodeljen rezultat poziva spoljasnje funkcije (tj. unutrasnja funkcija)
const unutrasnja = spoljasnja()
// unutrasnja funkcija povecava brojac iz roditeljskog opsega, i nakon što je roditeljska funkcija završena
console.log(unutrasnja())
console.log(unutrasnja())
Kako ovo radi? Zar ne bi trebalo da se, kada funkcija završi, sva memorija potrošena za njene lokalne varijable oslobodi automatskim sakupljanjem otpada? Da, kad funkcija završi, opseg se oslobađa jer više nije potreban. Međutim, u slučaju unutrašnje funkcije koja je vraćena i dodeljena varijabli, opseg unutrašnje funkcije pripaja se spoljnjoj funkciji, koja ostaje aktivna.
Primer: Pozdrav
function napraviPozdrav(ime){
const tekst = 'Zdravo ' + ime
return function() {
console.log(tekst)
}
}
const pozdrav1 = napraviPozdrav('Darko')
const pozdrav2 = napraviPozdrav('Azra')
pozdrav1()
pozdrav2()
Ovde unutrašnja funkcija takođe nastavlja da ima pristup varijabli tekst
iz spoljašnje funkcije, i nakon što je ona završena.
Primer: Zaštićena varijabla
Čest primer korišćenja zatvorenosti je kreiranje geter i seter funkcija, za uzimanje i postavljanje zaštićene vrednosti. Na primer, možemo “sakriti” promenljivu unutar funkcije, i napraviti dve dodatne funkcije za učitavanje i postavljanje njene vrednosti. Geter i seter funkcije moramo staviti unutar istog opsega u kom je promenljiva zasticeno
. Zatvoreni opseg pravimo pomoću samoizvršne anonimne funkcije:
let getValue, setValue
(function () {
let zasticeno = 0
getValue = function () {
return zasticeno
}
setValue = function (v) {
if (typeof v === "number"){ // provera tipa pre dodele vrednosti
zasticeno = v
}
}
}())
console.log(getValue())
setValue(123)
console.log(getValue())
Funkcije setValue()
i getValue()
proglašavamo kao globalne, da bi bile dostupne, dok promenljiva zasticeno
ostaje lokalna i nepristupačna.
Primer: Iterator
Možemo upotrebiti closure
da bismo postigli funkcionalnost iteratora. Postoje slučajevi kada nije dovoljno odjednom iterirati niz, već je potrebna pauza između iteracije elemenata. Na primer, možemo pozvati funkciju next()
svakog puta kada nam je potrebna naredna vrednost.
Funkcija napraviIterator
prima niz i definiše indeks i
, koji pamti trenutni element u nizu:
function napraviIterator(niz) {
let i = 0
return function() {
return niz[i++]
}
}
const next = napraviIterator(['a', 'b', 'c']) // vraca funkciju
// neprekidnim pozivanjem iste funkcije dobijamo naredni element
console.log(next())
console.log(next())
console.log(next())
Literatura
- Ved Antani, Stojan Stefanov, Objektno-orjentisan JavaScript, Beograd, 2017.