Definicija i karakteristike
Poznata je činjenica da kada se završi funkcija, sve njene lokalne promenljive pokupi garbage collector i one prestaju da postoje u memoriji. Medjutim to nije slučaj za funkciju koja unutar sebe sadrži closure funkciju.
Closure su funkcije koje imaju pristup promenjivima koje se nalaze u domenu druge funkcije. Ovo se najčešće postiže ugradjivanjem funkcije unutar druge funkcije (čime se definiše “scope chain”), nakon čega closure dobija sposobnost da zapamti referencu na promenjive iz parent domena.
Treba napomenuti da se promenjive spoljne funkcije ne brišu po izvršavanju same funkcije, već se čuvaju u memoriji da bi bile dostupne closure funkciji. Nakon izvršenja closure funkcije, zatvara se i spoljna funkcija (odatle i naziv “closure“). Dok god se closure ne izvrše, JavaScript će čuvati i potrebne promenjive iz domena drugih funkcija, stoga one zauzimaju više memorije nego obične funkcije. Preterano korišćenje closure može da dovede do povećenja potrošnje memorije. Najnoviji JavaScript engine uspevaju da delimično oslobode zarobljenu memoriju, ali je i dalje stoji preporuka da se bude pažljiv pri korišćenju closure.
U sklopu debuger-a ugradjenog u browseru, može da se vidi closure izraz i koja je vrednost pormenjive “zapamćena” (pogledaj sliku).
Primer standardne closure f-je
Funkcija b() je ugnježdena unutar funkcije a() i duž “scope chain” potražuje promenjivu iz funkcije a(), stoga je ona klasičan primer closure funkcije.
|
function a (){ var x = "Ovo je closure"; function b (){ console.log (x); } b(); } a(); Vraća: Ovo je closure |
Nije svaka ugnježdena funkcija i closure
Ukoliko unutrašnja funkcija ne koristi promenjivu iz spoljnih funkcija u kojim se nalazi (duž “scope chain”), to onda nije closure. Pogledaj naredni primer:
|
function a (){ var x = 5; function b (){ console.log ("Ovo je ugnjezdjena funkcija, ali nije closure!"); } b(); } a(); // Vraća: Ovo je ugnjezdjena funkcija, ali nije closure! |
Closure pamti promenjive iz spoljne funkcije čak iako je spoljna fukcija izvršena
Poznato je da se nakon korišćenja naredbe return prekida izvršenje funkcije i postojanje njenih promenjivih u privremenoj memoriji. Medjutim “Closure” pamti promenjive iz spoljne funkcije čak iako je vratila neku vrednost sa return.
|
function a () { var x = "Ovo je closure, čak i pošto je spoljna funkcija završena i vratila rezultat"; function b () { console.log(x); } return b; } var c = a(); //Dodeljujemo return funkciju promenjivoj "c" c(); // Vraća: Ovo je closure, čak i pošto je spoljna funkcija završena i vratila rezultat |
Closure “pamti” referencu na koju ukazuje promenjiva
Kada se kaže da “closure funkcija” ima pristup promenjivoj pod tim se misli da ima pristup odredjenom mestu u memoriji na koju ukazuje ta promenjiva tj. njenoj referenci u trenutku pozivanja “clousure funkcije“. Ukoliko se na tom mestu u memoriji tj. referenci menja vrednost, clousure će uvek uzeti najnoviju trenutnu vrednost. U narednom primeru se vidi kako unutrasnja funkcija “pamti” referencu i koristi trenutnu vrednost u memoriji.
|
function povecajBrojac () { var brojac = 0; return function () { return brojac++; }; } var izbroj = povecajBrojac(); izbroj(); // Vraća: 0 izbroj(); // Vraća: 1 izbroj(); // Vraća: 2 |
Redeklarisanje promenjive
Ako nakon definisanja clousure, promenjivoj koja je potrebna closure dodelimo neku drugu referencu (mesto u memoriji koje čuva neku vrednost), clousure će da koristi referencu koja je bila u opticaju u trenutku definisanja clousure. U sledećem primeru, funkcija sayHello() u trenutku definisanja “pamti” referencu na globalnu promenjivu “myName” (“Dragoljub”). Pa iako “myName” menja referencu koja sada sadrži vrednost “Marko”, closure i dalje koristi vrednost “Dragoljub”.
|
var myName = 'Dragoljub'; var pozdrav = function(name){ return function(){ console.log('Hello ' + name + '!'); } } var pozdravSaImenom = pozdrav(myName); myName = 'Marko'; pozdravSaImenom();//Vraća: Hello Dragoljub! |
Medjutim to ne znači da closure pamti prvu definisanu vrednost neke promenjive, već pamti definisanu vrednost promenjive u trenutku definisanja closure. Pa tako u sledećem primeru funkcija vraća “Marko”
|
var myName = 'Dragoljub'; var pozdrav = function(name){ return function(){ console.log('Hello ' + name + '!'); } } myName = 'Marko'; var pozdravSaImenom = pozdrav(myName); myName = 'Pera'; pozdravSaImenom();//Vraća: Hello Marko! |
NAPOMENA:
Kada se koristi ključna reč “new” za kreiranje objekta unutar neke spoljne funkcije, TO NE KREIRA CLOSURE i nova funkcija nema referencu na lokalnu promenjivu spoljne fukncije kao closure.
Continue reading…