Definicija

js this

Pojam “scope” (oblast definisanosti promenjive) je vezan za pojam promenjive i predstavlja deo programskog koda u kojoj je neka promenjiva dostupna. Osnovna karakteristika oblasti definisanosti je granica te oblasti. Promenjivoj se može pristupiti samo ukoliko je potražujemo u okviru njene oblasti definisanosti tj. ne može se pristupiti promenjivoj ukoliko se nalazimo izvan scope-a.

Treba napomenuti da “scope” nije isto što i “context”. Ova dva pojma se često mešaju jer imaju neke sličnosti ali treba znati da je pojam “scope” je osobina promenjive, dok je “context” osobina programskog koda. Tokom izvršavanja, program prolazi (ulazi i izlazi) kroz različite oblasti definisanosti promenjive (scope), a promenjive su tada ili u “context-u” ili ne. “Contex” je sličan oblasti definisanosti jer takodje zavisi od pozicije u programu (“lexical context”) ili vremena izvršavanja koda (“execution context”).

Podela prema vremenu definisanja

Statički (“lexical”) scope

Lexical scope se definiše u trenutku kompajliranja, tako da funkcija tada zapamti reference na koje ukazuju promenjive u lancu lexical scope (tzv. “RANO VEZIVANJE”)

“Lexical scope” direktno zavisi od mesta gde je deklarisana promenjiva u samom kodu, stoga se može zaključiti da se ovaj tip domena promenjive se definiše u trenutku pisanju koda. Shodno tome ovaj kod se ne može menjati tokom vremena (osim samim menjanjem koda), pa ga još zovu i “static scope”.
Jedini način da se “prevari” lexical scope je korišćenje naredbe eval, ali je preporuka da se ova naredba što manje koristi (neki ozbiljni programeri je čak kažu zovu “evil”). Ovaj tip oblasti definisanosti se koristi u većini programiskih jezika uljučujući i JavaScript.

Dinamički scope

Dinamički scope se definiše u vreme izvršavanja koda (runtime) pa se vezuje za reference na koje ukazuju promenjive u tom trenutku izvršavanja koda (tzv. “KASNO VEZIVANJE”)

Kod programskih jezika koje koriste dinamički scope, nakon potrage za promenjivom u okviru matične funkcije, kreće potraga za promenjivom u funkciji koja je pozvala matičnu funkciju. Dinamički skope je veoma teško pratiti, pa je zbog toga i manje zastupljen kod programskih jezika. Koristi se kod Lisp-a, Perl-a…

Podela prema veličini oblasti definisanosti

Lokalni scope

Sve do pojave ES6 u JavaScriptu je bilo moguće napraviti lokalni scope samo uz pomoć funkcije. Ovo je smatrano kao jedna od najvećih mana samog jezika. Ovo je ispravljeno sa novom revizijom jezika “ES6” uz pomoć rezervisane reči “let” koja definiše blok scope.

a) Function scope

Kada se promenjiva deklariše unutar funkcije ona definiše lokalni scope koji se još zove “function scope“.

Lokalna promenjiva (promenjiva unutar funkcija) i fuction scope postoje samo pri pozivanju funkcije (invoke function). Zbog toga posledanja naredba iz prethodnog primera izbacuje grešku, Gledano iz globalnog scopa, ako zanemarimo granice scopa, promenjiva “unutrašnja” ne postoji, jer je funkcija “odavno” izvršena tj. promenjiva je postojala u trenutku izvršenja ali nakon toga više ne postoji.

b) Block scope

EcmaScript 5 ne podržava “blok scope” (oblast definisana blokom koda) ali sa ES 6 je uvedena nova specijalna reč “let” koja deklariše promenjivu unutar bloka koda i samim tim definiše lokalni blok scope. Jedna od bitnih karakteristika kreiranja block scope sa ključnom reči let je da se pri tome ne izvršava hoisting! Stoga je neophodno stavljati deklaracije promenjivih na početak bloka.

Najčešće je blok koda definisan sa vitičastim zagradama kao u narednom primeru:

Specijalna reč “let” može da se nadje i van vitičastih zagrada a da njih definiše kao oblast definisanosti ako se koristi u sklopu for petlje.

Pored toga što deklariše lokalnu promenjivu u sklopu vitičastih zagrada, rezervisana reč “let” ponovo deklariše novu promenjivu “i” u svakoj iteraciji petlje. Sa ovim je rešen problem specifičan za ES5 kada closure vraća samo poslednje “i” ukoliko je i deklarisano sa “var”, što je prikazano na sledećem primeru:

NAPOMENA:
Treba pomenuti da je u ES5 pored function scope moguće napraviti novi blok scope sa delom koda koji rukuje sa greškama u kodu a definisan je sa specijalnom reči “catch”:

Ovaj način pravljenja lokalne oblasti definisanosti koriste transpileri, da bi napravili blok scope u ES5.

Globalni scope

Prema ES5 standardu svaka promenjiva koja nije definisana sa rezervisanom reči var u okviru funkcije pripada “globalnom scope-u” a to znači da je promenjiva dostupna svim delovima programa. U okviru browser-a globalni scope je window objekat, pa sve globalne promenjive postaju svojstva “window” objekta. “Životni vek” globalne promenjive traje dok se ne zatvori ili ponovo učita stranica tj. window objekat. Ukoliko se promenjiva ne deklariše sa rezervisanom reči var promenjiva će postati globalna pa čak i ako je definisana (dodeljena joj je vrednost) unutar funkcije.

Naješće se globalna promenjiva kreira greškom, pa je preporuka da se koristi striktni mod “use strict” koji pri kreiranju globalne promenjive prijavlljuje grešku.

Karakteristični primeri

Ugnježdene funkcije

Kada posmatramo neku promenjivu unutar funkcije (u trenutku pisanja koda) znamo da je dostupna u celoj funkciji. Ukoliko se unutar funkcije nalaze druge funkcije ona će biti dostupna i tamo. Što znači da je svakoj ugnježdjenoj funkciji dostupan spoljni deo koda (tzv. parent scope), tj. svaka promenjiva, funkcija ili objekat.
Kod jezika koji podržavaju lexical scope kompajler prvo traži promenjivu unutar same funkcije koja je pokrenuta, zatim traži u funkciji koja je izvan a sadrži funkciju,….i tako sve do globalnog domena gde takodje pretražuje promenjivu, tek ako je i tamo ne nadje onda vraća da je tražena promenjiva “undefined”.

Poziv funkcije ne generiše scope

Obratite pažnju da poziv funkcije unutar druge funkcije ne pravi lexical scope. Na sledećem primeru poziv za funkciju f2() se nalazi unutar funkcije f1(), ali to funkciji f2() ne omogućava pristup promenjivoj “a” deklarisanoj u funkciji f1(). Ovo se dešava jer naredba za pozivanje funkcije unutar f1() ne pravi “lexical scope”!

Shadowing (zaklanjanje promenjive)

U sledećem primeru IIFE ne nalazi promenjivu “x” u oviru svoje funkcije, pa je kompajler traži u parent domenu gde je i nalazi.

Ako se X deklariše i unutar IIFE, kompajler neće koristi promenjivu iz globalnog domena. Kompajler prvo pretražuje matičnu funkciju i kada nadje to što traži prekida pretragu. Ova pojava se zove “shadowing” (zaklanjanje promenjive).

Kompajler je nakon pretraživanja lokalnog domena zaključio da je u njemu deklarisana promenjiva X, promenjiva X nema vrednost u trenutku izvršenja linije koda sa console.log jer joj se vrednost dodeljuje kasnije. Sa gledišta kompajlera kod izgleda ovako:


Pogledajte slične članke...

Podelite:

Ostavite komentar