A JavaScript mélységei: Annyira tipikus

Ahogy ígértem, itt a sorozat első epizódja. A mai téma még nem túl bonyolult, de azért izgalmas...

Aki egy erősen típusos nyelv után kezd a JavaScripttel foglalkozni a következő sort látva előszőr általában meglepődik.

var alma;

A var kulcsszóból elég jól látható, hogy itt egy változó deklarációról van szó, azonban értékadás (inicializáció) nem történik, így látszólag semmilyen módon sem rendelünk típust az alma nevű változóhoz. De, akkor tulajdonképpen mi a típusa? Ehhez a kérdéshez eljutva sokan jutnak arra a téves következtetésre, hogy a JavaScript nem típusos nyelv és így aztán a változónknak nincs is típusa. Ezzel pedig eljutottunk az első rész témájához: Típusok a JavaScriptben.

De mielőtt rátérnénk a lényegre menjünk kicsit távolabb. Mi is az a típus (type)? Ha kicsit belegondolunk lényegében értékek (values) véges, vagy (elméletileg) végtelen halmaza. Például az egész (integer) típus jellemzően az egész számok halmazának egy részhalmazát szokta jelölni. Az hogy pontosan melyik részhalmazt nyílván nyelvfüggő, de a lényeget jól mutatja ez a példa.

Mivel valahogyan muszáj specifikálni, hogy mit is tartalmazhat egy változó, típusra mindenképp szükség van. De minek több típus? Hiszen végső soron sok 0 és 1 kerül a memóriába, akár számról, akár szövegről, akár valami összetett objektumról van szó. Egyfelől persze a mi kényelmünk miatt, hiszen jobb azt írni, hogy "barack", mint hogy 10111101101....01110111. De a lényeg nem ez, hanem a műveletek. Hiszen a különböző típusokra különböző műveleteket lehet alkalmazni. Például sok nyelvben (köztük a JavaScriptben is) a + jel más műveletet jelöl egy szöveg és más műveletet egy szám esetén:

Összeadás (szám + szám): 5 + 5 = 10
Összefűzés (szöveg + szöveg): "5" + "5" = "55"

Na most, ha a fordító (vagy interpreter) nem tudná, hogy a + jel két oldalán milyen típusú értékek állnak, akkor nem lehetne eldönteni, hogy a programozó melyik műveletre gondolt. Persze használhatnánk különböző jeleket a különböző művelet leírására, de ez a lényegen nem változtatna, azaz, hogy az összefűzés művelet csak a szövegek halmazán értelmezett, míg az összeadás csak a számok halmazán. Ergo elkerülhetetlen a típusok megkülönböztetése. Ezért aztán a JavaScript is típusos nyelv.

Típusok a JavaScriptben

Visszatérve a témához, akkor most mi is a típusa a változónknak? Hát az a helyzet, hogy egész idáig értékekről beszéltem és a típusok kapcsán a változókat nem is nagyon említettem. Tehát arról volt szó, hogy muszáj típust rendelni az értékekhez, hogy azokon műveleteket tudjunk végezni. Arról viszont nem eset szó, hogy muszáj lenne típust rendelni a változókhoz is.

Nem mondom, hogy nincsenek bizonyos előnyei annak, ha a változónak is van típusa, de az biztos, hogy ez nem szükséges feltétele annak, hogy egy nyelv működjön. Így aztán a JavaScriptben a változóknak (variable) nem csak az értéke, de a típusa is változó (variant). Egész pontosan a változó típusa mindig megegyezik a benne tárolt érték típusával.

Szuper, csak ez nekünk nem segít. Ha emlékszünk még, akkor a változónknak nem adtunk értéket. Szóval, akkor típusa sincs?

Típusrendszer

Eljött az ideje, hogy megnézzük, milyen típusokat határoz meg a JavaScript specifikációja:

  • Number (szám)
  • String (szöveg)
  • Boolean (logikai érték)
  • Object (objektum)
  • Null ("semmi")
  • Undefined (nem definiált)

Hát érdekes. Első ránézésre elég kevés, viszont annál furcsább. Az első három ugyebár elég egyértelmű, mondjuk kicsit több fajta szám típus szokott lenni, de nem baj, elmegy. Az objektum típus alapján e nyelv valószínűleg objektum orientált, hát ez is furcsa lehet, ha az ember tudja, hogy a JavaScriptben nincsenek osztályok. A Null még akár ismerős is lehet, hiszen C++-ban is van null pointer és más nyelvekben is előfordul ez. Úgy pedig, hogy tudjuk, hogy itt csak az értékeknek van típusa, nem is furcsa. Viszont az Undefined, mint típus már érdekes.

Ha valami nincs definiálva, vagyis inicializálva, akkor az tulajdonképpen nincs is, nem is létezik. Ami nincs, annak pedig típusa sincs, vagy ha mégis, akkor arra meg már ott a Null. Akkor meg minek az Undefined? Kivételesen a specifikációt hívom segítségül:

The Undefined type has exactly one value, called undefined. Any variable that has not been assigned a value
has the value undefined.

Tehát egy olyan halmazról van szó, aminek pontosan egy értéke van, a kisbetűs undefined. És ami fontosabb, bármely változó, amelyhez nem rendeltünk értéket automatikusan az undefined értéket kapja.

Ergo a JavaScriptben mindig, minden változónak van értéke és ebből következőleg típusa is. A mi változónk pedig jelenleg Undefined típusú és az undefined értéket tárolja.

Deklaráció és definícó

Az undefined ugyebár azt jelenti, hogy nem definiált. Viszont a deklarációról semmit sem mond. Nem véletlen.

A deklaráció és a definíció közötti különbség talán a C-ben érezhető a legjobban. A header fájlban deklaráljuk a változókat és ezáltal lefoglaltatjuk számukra a szükséges memóriaterületet. Majd a forráskódban (a c fájlban) definiáljuk őket, azaz itt rendelünk hozzájuk értéket.

A JavaScriptben a korábban leírtak alapján nincsen lehetőségünk egy változót csak deklarálni. Illetve értelme sem volna, hiszen, amíg nincsen értéke, addig típusa sincs, így addig azt sem lehet tudni, hogy mekkora memóriaterületet igényel. Azaz mikor mi explicit deklarálunk egy változót, akkor a valóságban deklaráljuk és implicit definiáljuk is.

Bár a JavaScript nem követi teljes mértékben a megszokott logikát, azért az elnevezések terén igyekszik megfelelni annak. Így, mivel mi logikailag csak deklaráltuk a változót, hiszen értéket explicit módon nem rendeltünk hozzá, a típusa Undefined lesz, azaz - logikai értelemben - nem definiált.

De nagyon fontos érteni, hogy ettől még deklarálva és fizikailag definiálva is van. Ugyanis, ha nem írjuk le a cikk elején szereplő sort, majd megpróbáljuk kiolvasni a változó értékét, akkor ReferenceError-t fogunk kapni, hiszen egy nem deklarált és nem is definiált változót próbálunk kiolvasni.

Remélem tetszett az első rész, jövő héten itt folytatjuk.