A Javascript programozási nyelv

Típusok, típuskonstrukciók

Típusszerkezet

A JavaScript dinamikusan tipizált nyelv. Ez azt jelenti, hogy nem kell deklaráláskor meghatározni egy változó adattípusát, és az adattípusok automatikusan konvertálódnak, ahogy az a script futása során szükséges. A JavaScript által megkülönböztetett adattípusok :

Adattípus neve Informatív leírás
number Szám változó, ami egyaránt tartalmazhat egész vagy valós számokat is.
string Karakterlánc változó. A konstansokat idézőjelek (") között adhatjuk meg, és használhatjuk a C-ben megszokott escape szekvenciákat is.
boolean Logikai változó. TRUE (igaz) vagy FALSE (hamis) értéket vehet fel. Ha számként használjuk, akkor a TRUE értéke 1, a FALSE értéke pedig 0 lesz.
undefined A változó létre lett hozva, de nem lett hozzárendelve érték. Arra vár, hogy értéket kapjon, és ekkor a típusa is megváltozik.
null Ez egy speciális adat, ami azt jelzi, hogy a változó nem tartalmaz semmit. Ha szövegként használjuk automatikusan átalakítja "null" értékké, ha számként, akkor 0-ává.
function Függvényváltozó. értéknek egy függvényt kaphat, amit akár meg is hívhatunk.
object Objektum változó, ami egy összetett adattípus.

Egy változó típusát a typeof unáris operátor segítségével kérdezhetjük le, ami a fenti értékek valamelyikét tartalmazó karakterláncot adja vissza.

result = typeof variable; function semmi(){}; typeof semmi() == "undefined" typeof semmi == "function" typeof new semmi() == "object"

Elemi típusok

Szám típus

Számokat megadhatunk lebegőpontosként, illetve egész számként. A JavaScript három számrendszert használ:

  1. Decimális: nincs külön megjelölése, de a szám nem kezdődhet 0-val (pl.: 129)
  2. Oktális: a szám 0-val kezdődik (pl.: -0711)
  3. Hexadecimális: a szám 0x-szel kezdődik (pl.: 0xFA12)

Lebegőpontos esetben a szám három komponensből áll:

  1. egészrész (ha ez nulla, akkor nem kell kiírnunk)
  2. tizedespont, és a törtrész
  3. az exponens, mely E-vel, vagy e-vel kezdődik, és mögötte lehet negatív illetve pozitív szám
A számok alapértelmezetten egész számok, lebegőpontossá akkor válnak, ha tizedespont, vagy "E" található a számban. Például: 3.14, -3.1E-2, .1E12, 2E2

Logikai típus

Logikai változó. TRUE (igaz) vagy FALSE (hamis) értéket vehet fel. Ha számként használjuk, akkor a TRUE értéke 1, a FALSE értéke pedig 0 lesz.

Sztring típus

Lásd még: sztring literálok
A sztringek kétféleképp lehetnek jelen egy Javascript programban: literálként, illetve String objektumként. Például:

var literal = "Ez egy string literál"; var obj = new String("Ez egy String objektum"); var literal2 = String("A new operátor nélküli konstruktor hívás literált eredményez.");

A literálokra, és az objektumokra is használhatóak a String objektum függvényei. A különbség a két forma között az, hogy a literálokhoz nem lehet dinamikusan új tulajdonságokat rendelni. Ennek oka, hogy a literálon végzett bármely művelet során a háttérben egy temporális String objektum jön létre a literál tartalmával. A Javascript String objektumai immutable objektumok, azaz egy-egy objektumon nem végezhető módosítás, helyette a műveletek egy új, módosított objektumot adnak vissza. String objektumok többek, mint egyszerű karakter tömbök, de tömb módjára is indexelhetőek [] operatorral. Ez azonban csak a Mozilla alapú böngészőknél működik. Általánosan a charAt(...) függvény használható indexelésre. A immutable tulajdonság miatt hibának számít, ha egy String i. karakterének értéket próbálunk adni. Pl.

var greeting = new String("Hello, world!"); greeting[0] = "H"; // ERROR

A Stringek összehasonlítására az "==" operátor használható, mely tartalom szerint hasonlít össze. Ez hossz szerint, ill. kis-, és nagy betű szerint is különbséget tesz. Stringek konkatenálására használhatóak a túlterhelt "+", és "+=" operátorok.

Felsorolási típus

A nyelvben nincs explicit konstrukció felsorolási típusra, de szimulálhatóak objektum-literálokkal. Például:

var Colors = {RED: 0, GREEN: 1, BLUE: 2}; var theColor = Colors.RED;

Típuskonstrukciók

Tömb típus

Az elemi értékekből tömböket állíthatunk össze, és ahogy a változók esetében, a tömbök egyes elemeinek sincs meghatározott típusa, és ráadásul a tömb bármely eleme lehet tetszőleges típusú, azaz egy tömbben többféle típusú adat is előfordulhat. Tömböket az alábbi módokon hozhatunk létre:

  1. Konstruktor hívással, opcionálisan a kezdő tömbméretet paraméterként átadva

    var longVector = new Array(1000); // 1000 elemű tömb var shortVector = new Array(); // 0 elemű tömb, ua., mint var shortVector = [];
  2. Konstruktor hívással, a tömb elemeit paraméterként átadva

    var evens = new Array(0,2,4,6,8);
  3. Tömbliterál létrehozásával, az elemeket "[" és "]" között felsorolva

    var odds = [1,3,5,7,9];
  4. Generátorok használatával ("Array comprehensions")
    Lásd. még Generátorok c. rész.

    function range(begin, end) { for (let i = begin; i < end; ++i) { yield i; } } var ten_squares = [i * i for each (i in range(0, 10))]; var even_squares = [i * i for each (i in range(0, 21)) if (i % 2 == 0)];

    A generátorok használatával a tömbinicializáció tömörebbé tehető. A szintaxis a tömbliterál létrehozásához hasonlít, de az elemeket nem mi soroljuk fel explicit, hanem egy speciális függvényt (a generátort) iterálva kapjuk (for each). A generátor által visszaadott értékeket egyenként transzformálhatjuk (a példában i*i), és szelektálhatjuk is (a második példában alkalmazott if-fel).

A tömb elemeire egyenként hivatkozhatunk, az elemek indexeivel (0,1,2 .. ), illetve hivatkozhatunk az egész tömbre egyszerre is a tömb nevével. Egy tömb hosszát, azaz elemeinek számát lekérdezhetjük a length propertyvel. A hagyományos értelemben nem kezeljük a tömb elemszámát, azaz egy három elemmel deklarált tömbnek lekérdezhetjük a 4. elemét is (3-as index), amely ekkor undefined lesz. Sőt a tömböt tetszőlegesen bővíthetjük is úgy, hogy egy olyan indexű elemének adunk értéket, amely eddig undefined volt. Ekkor az új indexet megelőző elemek, amelyeknek nem adtunk értéket, szintén undefined-ok lesznek. Például:

NextArray = [1, 2]; // ekkor például NextArray[10] = undefined lesz, NextArray.length értéke 2 NextArray[3] = 4; // ekkor NextArray[2] = undefined lesz, NextArray.length értéke 4

Továbbá létrehozhatunk úgy is tömböt, hogy nem minden elemének adunk meg értéket. Ha a definiáláskor kihagyunk elemek, akkor azok értéke szintén undefined lesz. Például:

NewArray = [, "második elem", , "negyedik elem"];

A nyelvben nincsenek többdimenziós tömbök, helyettük a tömbök tömbje használható. Például:

var twoDim = [ [11,12], [21,22] ];

A Javascript tömbjei, mivel méretük változhat, használhatóak lista adatszerkezetként is. A tömb azonban szinte minden más alapvető adatszerkezet szerepét képes eljátszani:

Asszociatív tömb

A tömbök indexelésére pozitív egészek helyett használhatunk Stringeket is. Ekkor használható a . operátor az egyes tömbelemek eléréséhez Például:

var myArray = new Array(); myArray["a"] = 100; myArray["c"] = 200; myArray["a"] == myArray.a == 100 // . operator használata

Innen már látható, hogy a háttérben valójában egy "a" nevű propertyt hoztunk létre a myArray objektumon a 100 értékkel, mely kétféle szintaxis szerint érhető el (vö. myArray.lenght == 0 !!). Ebből következően, mivel ezt bármilyen objektummal megtehetjük, bármilyen objektum használható asszociatív tömbként. Pl. (vö. "{ }" - objektum-literál a "[ ]" - tömb-literál helyett) Mégis a tömböket érdemes erre a célra használni, egyrészt az átláthatóság miatt, másrészt, a tömb objektum plusz szolgáltatásai (pl. a rendezésre: sort() függvény) miatt.

var myArray = { "abc":200, "xyz": 300}; // tetszőleges új objektum tömbbé erőszakolása alert(myArray["abc"]); // output: 200
Verem

A tömbök rendelkeznek push(), és pop() műveletekkel, melyek a tömb végére tesznek be egy elemet, illetve vesznek el onnan. A verem többi jellemző művelete a tömb hosszának és az indexelésnek a használatával oldható meg.

Sor

A shift() függvény kilépteti az első elemet a tömbből, míg az unshift() belépteti a tömb elejére a tetszőleges számú paraméterét.

Tömb metódusok, és Array extras

A tömb objektumokra használható függvények köre az 1.6-os verzióval jelentősen bővült. Az alábbi táblázat összefoglalja a régi és az új függvényeket: A Javascript verzió oszlopban, ha nincs külön jelölve verzió, akkor az 1.5-ös változatban használható a függvény. A böngésző verzió oszlopban az IE az Internet Explorer, a Moz a Mozilla, ill. az FF a Firefox verzióit jelöli.

Szignatúra Leírás Javascript ver. Böngésző ver.
concat(value1[value2[value...]]) Egyetlen tömbbé konkatenálja a paramétereket, melyek lehetnek tömbök, de egyszerű értékek is. IE4, Moz 4.0
every(function) Ellenőrzi, hogy a paraméterként kapott, logikai értékű függvény a tömb összes elemére igaz-e. 1.6 ?, FF1.5
filter(function) A paraméterül kapott függvényre igazat adó tömbelemeket tartalmazó új tömböt ad vissza. 1.6 ?, FF1.5
forEach(function) A paraméterül kapott függvényt a tömb minden elemére végrehajtja. 1.6 ? FF1.5
join(delimeter) A tömb elemeinek felsorolásából álló Stringet ad vissza, melyben az elemeket a paraméterül átadott delimiter választja el. IE3.0, Moz 3.0
indexOf(searchStr[, startIndex]) Megkeresi a searchStr első előfordulását (opcionálisan a startIndextől kezdve) a tömbben. Ha nincs, az eredmény -1. 1.6 ?, FF1.5
lastIndexOf(searchStr[, startIndex]) Az előzővel ellentétben az utolsó előfordulást keresi. 1.6 ?, FF1.5
map(function) A paraméterül kapott transzformáló függvényt alkalmazza a tömb minden elemére, és a transzformált elemek tömbjével tér vissza. 1.6 ?, FF1.5
pop() Eldobja a tömb utolsó elemét. IE5.5, Moz 3.0
push(value[,value2[, value...]]) Hozzáfűzi a tömb végére a paramétereket. IE5.5, Moz 4.0
reverse() Megfordítja a tömb elemeinek sorrendjét. IE3.0, Moz 3.0
shift() Kilépteti a tömb első elemét a tömbből. IE5.5, Moz 4.0
slice([begin[, end]]) Az egész tömbről, vagy a paraméterek által megadott indexhatárok közötti részről másolatot készít. IE4.0, Moz 4.0
some(function) A paraméterül kapott függvényt addig alkalmazza a tömb elemeire, míg a függvény igazat nem ad. Ekkor a visszatérési érték igaz, egyébként hamis. 1.6 ?, FF1.5
sort([function]) Paraméter nélkül alfabetikusan, paraméterrel az átadott rendező logika szerint rendezi a tömb elemeit. IE3.0, Moz 3.0
splice(start[, howmany[, element1[,element...]]]) A start indextől kezdve howmany darab elemet töröl a tömbből, és egy, a törölt elemekből álló tömböt ad vissza. IE5.5, Moz 4.0
toSource() A tömböt leíró forráskódot adja vissza. -, FF1.5
toString() A tömb String reprezentációját állítja elő. (Sajnos az objektumokra csak "[object]"-et ír.) IE3.0, Moz 3.0
unshift(value1[, value2[, value...]]) A tömb elejére belépteti a megadott paramétereket. IE5.5, Moz 4.0
Array.reduce(callback[, initialValue]) Akkumulatív számítást végez a callback paraméterrel, és initialValue kezdőértékkel balról-jobbra haladva. 1.8 FF3.0
Array.reduceRight(callback[, initialValue]) Mint a reduce, csak jobbról-balra halad. 1.8 FF3.0

A tömbök referencia szerint adódnak át. Az érték szerinti átadás szimulálására használhatjuk a slice() függvényt, ami egy másolatot készít az egész tömbről.

Direktszorzat típus

Rekordok

A nyelvben lehetőségünk van rekordok kezelésére is, ahol az elemekhez csak a beállított azonosító (kulcs) alapján hivatkozhatunk. A benne található elemek lehetnek objektumok, függvények, változók, elemi értékek, vagy akár más objektumtömbök is. A deklarálás itt is az elemek felsorolásával történik, amit "{" és "}" közé helyezünk, az elemeknél először az azonosítót, majd az értéket adjuk meg. Itt a téves kulccsal történő hivatkozás már nem undefined értékhez vezet, hanem hibához. Egy érdekes megközelítés, hogy amennyiben ez a kulcs egy pozitív egész szám, akkor használhatjuk a szokványos tömböknél használt indexszel való elérést, sőt, csak ilyen módon érhetjük el az adott értéket. Például:

var v1; function f1 { // valamilyen visszatérési érték } ARecord = { a: "szöveg", b: f1, 7: v1; } // ekkor például a következő hivatkozások érvényesek: ARecord.a, ARecord[7] // viszont ezek hibához vezetnek: ARecord[a], ARecord[0], ARecord.7

Rekordokba beágyazhatunk más rekordokat is, és rekurzívan folytatva tetszőlegesen mély szinteket hozhatunk létre.

BRecord = { a: { a: "belső1", 2: "belső2" } , 3: "külső2" } // ekkor a következő hivatkozások érvényesek: BRecord.a.a, BRecord.a[2], BRecord[3]

Típuskonverziók

A JavaScript dinamikusan tipizált nyelv. Ez azt jelenti, hogy nem kell deklaráláskor meghatározni egy változó adattípusát, és az adattípusok automatikusan konvertálódnak, ahogy az a script futása során szükséges. Ha egy változót olyan helyen használunk, ahol a típusa nem megfelelő, a JavaScript automatikusan megpróbálja (ami néha igen szélsőséges helyzetekben is sikerül neki) a megfelelő típusra konvertálni. A leggyakrabban a számok és a karakterláncok között fordul elő.

"dog" + "house" == "doghouse" // összekapcsolta a két karakterláncot "dog" + 4 == "dog4" // a számot átalakította 4 + "4" == "44" // karakterláncá 4 + 4 == 8 // összeadta a két számot 23 - "17" == 6 // a karakterláncot átalakította számmá function semmi(){}; "a"+semmi() == "aundefined" "a"+semmi == "a\nfunction semmi() {\n}\n" // Ez igen !! 4+semmi == ? // Na ez már nem megy! viszont: min("Aw", "A" + min(9)) == "Aundefined" // min(9) == undefined, ezt string-gé konvertálja

Változók, konstansok

Változók

A változókat a láthatóság szempontjából két csoportba oszthatjuk. Globálisak vagy lokálisak. A Javascript 1.7-es verziója óta lokális változóról kétféle értelemben beszélhetünk: függvény szintű lokális (var kulcsszóval deklarált), illetve blokk szinten lokális (let kulcsszóval deklarált) (lásd. még Változók hatóköre). (A korábbi verziókban lokális változó létrehozására csak a függvény szintjén lokális deklarációval volt lehetőség a var kulcsszóval.) Ha változót függvényen kívül, vagy függvényben kulcsszó nélkül deklarálunk, a változó globális lesz. Utóbbi azonban a nyelv 1.5-ös verziója óta nem megengedett.
Egy változót többször is deklarálhatunk, hiszen ez a nyelv számára nem jelent többet egy értékadásnál. Ha még nem adtunk értéket a változónak, és var nélkül deklaráltuk, kiértékelésének eredménye futási idejű hibát fog kiváltani, míg ha használtunk var kulcsszót, az eredmény undefined érték lesz, amely logikai műveletben hamisat jelent. Ha pedig egy változónak a null értéket adtuk, akkor szöveges műveletben "null" szövegként, számításban nulla értékként helyettesítődik be.

var a = 1; function main() { b = 1; var d = 3; someFunction(d); } function someFunction(e) { var c = 2 //... }

Az undefined értéket használhatjuk például arra is, hogy megállapítsuk, egy változó kapott-e már értéket.

var valtozo; //... if (valtozo == undefined){ // ha még nem kapott értéket }

Ebben a példában az a és a b egyaránt globális változók. Az egyes függvényeken belül a következo változókat lehet elérni:

main() someFunction()
a, b, d a, b, c, e

Az is lehetséges (bár nem ajánlott), hogy ugyanaz legyen egy lokális és egy globális változónak is a neve. Ebben az esetben a globális változóra mint a global objektum egy property-jére hivatkozhatunk (global.változónév), a név egyszerűen leírva a lokális változóra fog hivatkozni.
Amennyiben nem használtunk var kulcsszót, lehetőségünk van a változó törlésére is a delete operátorral. Kiadása után az adott változó már nem elérhető. Például:

g = 100; delete g;

Változónév lehet betűvel, aláhúzással (_), vagy dollár jellel ($) kezdődő karaktersorozat, mely ezeken kívül tartalmazhat számokat is a későbbi karaketerekben. Mivel a nyelv ügyel a kis- és nagybetűkre, használhatjuk ugyanazon neveket ezek variálása mellett, például az "A110" és az "a110" két külön változónak a neve.
A JavaScript 1.3-tól a nyelv kódolása Unicode karakterkészletet használ, ezért ennek a szabványnak megfelelően használhatunk ékezetes betűket is a változónevekben, akárcsak a Javaban.
A következő szavaknak speciális jelentése van az értelmező számára, ezért nem alkalmazhatjuk őket változóneveknek.

break case catch class const
continue debugger default delete do
else enum export extends false
finally for function if import
in new null return super
switch this throw true try
typeof while with var void
Változók hatóköre

Ha egy változó azonosítót függvényen kívüli hozzárendeléssel állítunk be, akkor azt globális változónak hívjuk, mert az aktuális dokumentumból bárhonnan elérhető. Ha egy változót egy függvényen belül deklarálunk, azt helyi változónak nevezzük, mert csak az adott függvényen belül érhető el.
A var kulcsszó használata globális változó deklarálásakor opcionális. Viszont, használnunk kell a var kulcsszót változó függvényen belüli deklarálásakor.
A nyelv 1.7-es verziója óta a let kulcsszóval is deklarálhatóak változók, melyek blokk szinten lesznek lokálisak. A let kulcsszó többféleképp használható:

"let statement"

A let kulcsszó után kezdőérték-adásokkal felsorolhatunk nulla, vagy több (akár a jelenlegi hatókörben lévőket elfedő) változót, melyek az ez után következő blokkban lokálisak lesznek.Például:

var x = 5, y = 0; let (x = x+10, y = 12) { print(x+y + "\n"); } print((x + y) + "\n");

Az output :

27 5
"let expression"

Az előző lehetőség egyszerűsített változata, melyben nem egy blokk áll a let deklarációk után, csak egyetlen kifejezés. Ilyenkor eköré implicit odaértendő a blokk kapcsos zárójel párja. Például az előbbi példa egyszerűbben:

var x = 5, y = 0; document.write( let(x = x + 10, y = 12) x+y + " "<br>\n"); document.write(x+y + " "<br>\n");

Az output természetesen ugyanaz, mint az előbbi példában.

"let definition"

Egy, a let definíciót tartalmazó blokkon belül hoz létre új, lokális változót. Abban különbözik a var kulcsszóval történő deklarációtól, hogy a var esetében a változó hatóköre az egész függvény, míg a let esetében csak az őt tartalmazó blokk. Ez a különbség ott figyelhető meg, hogy ha például egy függvényen belül egy ciklus magjában let definíciót használunk, akkor a ciklusból kilépve, de még ugyanabban a függvényben, a változót már nem tudjuk elérni. Például:

function varTest() { var x = 31; if (true) { var x = 71; // ugyanaz a változó! alert(x); // 71 } alert(x); // 71 } function letTest() { let x = 31; if (true) { let x = 71; // másik változó alert(x); // 71 } alert(x); // 31 }

A let definíció használata globális környezetben értelmetlen, nem definiál globális változót. A let definíció használható for, ill. for...in ciklus ciklusváltozójának deklarálására, a változó hatásköre a ciklusmag lesz.

Egy ablakon vagy kereten belül deklarált változó más ablakból vagy keretből történő eléréséhez meg kell adni az ablak vagy keret nevét. Például, ha a phoneNumber változót egy FRAMESET dokumentumban deklaráltuk, akkor a változóra egy gyermek keretből parent.phoneNumber módon hivatkozhatunk.

Konstansok

A JavaScript 1.5-től lehetőségünk van konstans változók megadására is, amelyek értékét nem módosíthatjuk a szkript lefutása során. A konstansok esetében a const kulcsszót kell használnunk, nevének pedig ugyanazon feltételeknek kell eleget tennie, mint a változóknak. Konstansokat deklarálhatunk alprogramon belül és kívül is, a kívül deklaráltak globálisan elérhetőek. Például:

const a = '12';

Kifejezések, operátorok

Kifejezések

A kifejezés literálok, változók, operátorok és utasítások kombinációja, amely kiértékelése egyetlen értéket eredményez.
A JavaScriptben az alábbi kifejezések találhatók:

Operátorok

A JavaScript operátorai nagyrészt megfelelnek a C, illetve Java nyelvekben használatos operátoroknak, és meghatározott precedenciasorrenddel rendelkeznek. Az operátorok csoportosítása:

  1. Értékadás
    Hasonlóan a fenti két nyelvhez, az értékadásnak itt is megtalálhatjuk számos változatát, melyek az értékadáson felül valamilyen más műveletet is elvégeznek a bal-, illetve jobboldali operandusokkal. Például az x*=y utasítás jelentése x=x*y.
  2. Összehasonlítás
    Az összehasonlítások logikai értékekkel térnek vissza. Egyenlőség esetén vizsgálhatjuk csak az értéket (==), valamint a típus egyenlőségét is (===). Előbbi esetben a nyelv automatikusan konvertálja az értéket, hogy a bal-, és jobboldal típusa megegyezzen. Utóbbinál ez nem történik meg.
  3. Aritmetikai
    növelés (++), csökkentés (--), negáció (-), illetve a moduló (%)
  4. Bitenkénti
    A bitenkénti operátorok használatakor az operandusokat először 32 bites számokká konvertáljuk, majd ezeken a biteken egymás után alkalmazzuk a műveletet. Például bitenkénti és esetében "15 & 9" eredménye 9 lesz.
  5. Logikai
    A nyelv a logikai és, illetve vagy műveleteknél lusta kiértékelést használ, azaz ha már a kifejezés első tagja megadja az eredményt, a második tagot már nem is veszi figyelembe. Például "false && bármi" esetén az eredmény hamis lesz, és ezért nem kell megnézni, mi van a bármi helyén.
  6. Sztring
    A sztringekre az összehasonlító operátorokon kívül a konkatenáció operátort (+) is lehet használni. Ez az operátor két sztringet összekapcsol és visszatér a két operandus sztring uniójaként kapott sztringgel. A rövidített értékadó operátort (+=), szintén lehet használni sztringek konkatenálására.
  7. Különleges
    ide tartozik minden más operátor:
    • feltételes kiértékelés (a ? b : c): a logikai értékétől függően b-t, vagy c-t adja vissza
    • vessző: tömbelemek felsorolásához
    • delete: objektumtörléshez
    • in: objektum bejárásához
    • instanceof: objektum típusának lekérdezése
    • new: új objektum létrehozása
    • this: saját objektum
    • typeof: objektum típusának lekérdezése
    • void: kifejezés kiértékelése visszatérési érték nélkül