JavaScript primitívek és objektumok, Objektumorientált programozás, osztályok, öröklődés.

Típusszerkezet


A JavaScript egy típustalan nyelv, ami annyit takar, hogy a változó értékének megadásával automatikusan hozzárendelődik a változóhoz a neki megfelelő adattípus. Amennyiben egy adott változó típusát szeretnénk lekérdezni, ehhez a typeof unáris operátort használhatjuk. A visszatérési értéke string típusú szöveg lesz, ami a típust jellegét taglalja.

console.log(typeof 36);  
// number

Amikor primitív típusokat használunk, akkor azok értékei átmásolhatóak egy változóba. Ellentétben az összetett típusokkal (például objektumok esetén), amikor a változóban az összetett adattípus memóriacíme tárolódik el. Összefoglalva: a primitívek az értékük szerint, az összetett típusok pedig a hivatkozásuk szerint másolódnak.

// példa primitív típusra
let x = 20;
let y = x;
x = 10;

console.log(x);
// 10
console.log(y);
// 20

// példa referencia típusra
let z = {kulcs: 20};
let v = z;
z.kulcs = 10;

console.log(z);
// {kulcs: 10}
console.log(v);
// {kulcs: 10}

A primitív és összetett típusok közül a leggyakrabban használtak az alábbiak:

  • Number (szám): olyan primitív adattípus, melyek értékei lehetnek a mínusz végtelen és plusz végtelen közé eső egész és valós (lebegőpontos) számok. Ezen belül háromféle számrendszerben ábrázolhatjuk a számokat: decimális, oktális valamint hexadecimális.

  • String (sztring): olyan primitív adattípus, melynek értékei lehetnek szimpla (''), vagy dupla ("") idézőjelek közé írt, tetszőleges hosszúságú karaktersorozat.

  • Boolean (logikai): olyan primitív adattípus, melynek értékei lehetnek igaz (true) vagy hamis (false). Számokkal kifejezve 0 vagy 1.

  • Null : olyan primitív adattípus, melyet a null érték tárolásához használják. A null elnevezés adattípust és értéket is jelent.

  • Undefined : olyan primitív adattípus, melyhez az undefined (definiálatlan) érték tartozik.

  • Object (objektum): olyan összetett adattípus, mely számos érvényes adattípusú elemmel rendelkezhet. Az objektumokat érdemes bizonyos szempontok szerint csoportosítani:

    • Fundamentális objektumok:

      • Object (objektum): Tetszőleges objektumot létrehozó összetett adattípus.

      • Function (függvény): Függvények létrehozásához használatos objektum.

      • Boolean (logikai): A primitív adattípusnak megfelelő Boolean objektum.

      • Error (hiba): Különféle hibakeresést segítő objektumok.

    • Számok és dátumok:

      • Number (szám): A primitív adattípusnak megfelelő Number objektum.

      • Math (matematika): Matematikai objektum különböző matematikai állandók és függvények eléréséhez.

      • Date (dátum): Dátum adattípus dátum kezeléséhez, és különböző dátumokkal kapcsolatos állandók és függvények eléréséhez.

    • Szövegfeldolgozás:

      • String (sztring): A primitív adattípusnak megfelelő String objektum.

      • RegEx (reguláris kifejezés): Mintaillesztő kifejezés létrehozásához használatos adattípus.

    • Index szerint azonosítható adathalmazok:

      • Array (tömb): Olyan adatstruktúra, ami több értéket tartalmazhat és elemei számozással indexelődnek.
    • Kulcs szerint azonosítható adathalmazok:

      • Set (halmaz): olyan adatstruktúra, melyben az összes elem (legyen az primitív érték vagy objektum) egyszer szerepelhet.

      • Map (Map): Olyan adatstruktúra, melyben az adatok kulcs-érték párokban léteznek és számít az adatok sorrendje (kulcs).

    • Struktúrált adatok:

      • JSON (JSON): Olyan adatstruktúra (és egyben szöveges fájlformátum), amiben ami több értéket tartalmazhat és egy érték többször is szerepelhet.
    • Node (csomópont): A HTML dokumentum és a JavaScript között az objektum modell a Node. A Node alatt szereplő adattípusok a HTML DOM által definiált objektumtípusok.

Típuskonverzió


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. Egy kifejezésen belül egy sztring és szám értékek + összeadás operátorral összeragasztva a JavaScript a számot sztringgé alakítja át.

var valtozo = 36;
console.log(typeof valtozo);  
//  number
valtozo = 'ezegysztring';
console.log(typeof valtozo);  
//  string
valtozo = 'masiksztring' + 46;
console.log(typeof valtozo);   
//  string

Primitív típusok


JavaScriptben a primitív típusok közül az undefined és a null kivételével automatikusan objektummá alakulnak át abban az esetben, mikor meghívjuk valamely metódusát. Tehát létezik a neki megfelelő objektum társa. Rögtön a meghívás után automatikusan visszaalakulnak primitívvé. A primitívek egy másik tulajdonsága az, hogy immutable-ok, azaz az értékük nem változhat. A primitíveket az értékük szerint lehet másolni.

// példa primitív típusra
let x = 20;
let y = x;
x = 10;

console.log(x);
// 10
console.log(y);
// 20

Number


Számokat megadhatunk lebegőpontosként, illetve egész számként. A JavaScript négy számrendszert használhatunk.

Az egész számokat bináris, decimális, oktális, valamint hexadecimális formában fejezhetjük ki. Szintaxisuk (a megkötésekkel együtt )a következőképpen néz ki:

• bináris forma: az első két karaktere (prefixum) 0b vagy 0B; karakterei állhatnak (0-1) számokból.

• oktális forma: az első két karaktere (prefixum) 0o vagy 0O; karakterei állhatnak (0-7) számokból.

• decimális forma: az első karakter nem lehet 0 szám; karakterei állhatnak (0-9) számokból.

• hexadecimális forma: az első két karaktere (prefixum) 0x vagy 0X; karakterei állhatnak (0-9) számokból és (a-f vagy A-F) betűkből.

// példa bináris literálra
0b1111
// példa oktális literálra
017
// példa decimális literálra
17
//példa hexadecimális literálra 
0xF

A lebegőpontos számok a következő részekből tevődik össze (balról jobbra olvasva):

• decimális egészrész, ahol előjelek (+ vagy -) szerepelhetnek.

• tizedesjel (.)

• decimális törtrész

• exponens rész; (e vagy E) karakter után decimális egészrész (+ vagy -) előjellel

// példa lebegőpontos számra
3.14
// példa lebegőpontos számra1.602176487E−19

Boolean


A boolean típusú változónak két értéke lehet: igaz (true) vagy hamis (false). Számokkal kifejezve 0 vagy 1. Nem összetévesztendő a primitív logikai értéket a logikai objektummal (mint összetett adattípus), melyek primitív logikai értékkel térnek vissza.

// példa logikai literálra
true
// példa logikai literálra
false

String


A sztringek literál és objektum formában lehetnek jelen a JavaScriptben. A JavaScriptben a literálokra ugyanazokat a metódusokat használhatjuk, mint a String objektum megfelelőikre. A két forma közti különbség az, hogy az előbbihez nem lehet új tulajdonságokat rendelni. Ennek oka, hogy a rajtuk végzett tetszőleges művelet során valójában létrejön ideiglenesen egy String objektum, melynek tartalma megegyezik a literáléval. Magukon a String objektumokon sem végezhető módosítás, ehelyett a műveletek egy teljesen új és módosított objektumot adnak vissza.

// példa sztring literálra
var literalforma = "ezegysztringliterál";
// példa sztring objektumra
var objektumforma = new String("ezegysztringobjektum");

Null


A Null egy olyan primitív adattípus, melyet a null érték tárolásához használják. A null elnevezés adattípust és értéket is jelent. Lényegében azt jelenti, hogy egy adott változó nem tartalmaz semmit. Nem alakítható át ideiglenesen objektummá.

var valtozo = null;
console.log(valtozo); 
// null 

Undefined


Az Undefined egy olyan primitív adattípus, melyhez az undefined (definiálatlan) érték tartozik. Nem alakítható át ideiglenesen objektummá.

var valtozo;
console.log(valtozo); 
// undefined 

Összetett típusok


Amikor összetett típusokat használunk (példéul Object), akkor azok nem mentődnek el változókban (mint egy primitív típus), hanem csak annak a memóriacíme.

// példa referencia típusra
let z = {kulcs: 20};
let v = z;
z.kulcs = 10;

console.log(z);
// {kulcs: 10}
console.log(v);
// {kulcs: 10}

Objektum-orientált programozás

Bevezető


Az objektum-orientált programozás egy olyan programozási paradigma (stílus), aminek a fókuszpontjában az objektumok helyezkednek el, a függvények helyett. A programozási paradigma útmutatást takar, ami közvetlenül érinti mind az adatok (és azok feldolgozását is), mind az eljárások vagy parancsok strukturálását és modellezését. Közvetve pedig kijelölheti azon problémák témakörét, melyek megoldására az adott nyelv a legoptimálisabb lehetőséget nyújtja. Az új paradigmák kialakulását új programozási módszerek megjelenését eredményezi. A paradigmák fejlődése gyakran az absztraktciós szint növekedésével járhat. Az objektum-orientált programozást megelőzően az imperatív paradigma létezett, aminél a program állapotát utasítások változtatták meg. Az imperatív programozás egyik típusa a proceduláris programozás, melynél a parancsok szubrutinokba (függvényekbe és eljárásokba) vannak foglalva. A változók és függvények egymástól elszeparálódnak. Ez a megközelítés hatékony és előremutató amíg viszonylag kevés sort tartalmazó programokról beszélünk. Amint a programot elkezdjük bővíteni, egyszercsak a változókat és a függvényeket egymás hegyén-hátán találhatjuk. Rengeteg alkalommal rákényszerülünk az egyes programrészek másolására, ami kizárja az újrafelhasználhatóságot. A probléma feloldására találták ki az objektum, majd az osztály végül az objektum-orientáltság (mint az imperatív programozási stílus egy másik típusa) elvét.

Programozási paradigmák

Egyik tulajdonsága az öröklődés koncepciójának megjelenése. A legtöbb objektum-orientált paradigmájú nyelv osztály alapú, tehát az objektumok az osztályok példányai. Kivételt képez a JavaScript, ahol az öröklődést (a kód újrafelhasználását) prototípusok segítségével is megoldható (ami szintén egy objektum). Az objektum-orientált programozás során az objektumok egységbe zárják az adatokat (tulajdonságokat), valamint a hozzá tartozó függvényeket (metódusokat). Egy objektum függvényei (metódusai) általában az objektumhoz tartozó adatokon végeznek műveleteket. Egy objektum-orientált stílusban megírt programot ilyen egymással kommunikáló objektumok összességét értjük. Számos programozási nyelv támogatja az objektum-orientáltságot, például C, C++, Java, JavaScript, és még sorolhatnánk. A prototípusság lényegében azt takarja, hogy egy objektumot egy másik mintájára tudunk elkészíteni. Erre többféle megközelítést ismerünk. Az egyik megközelítés szerint a készítendő objektum egy hivatkozást tartalmaz a másolni kívánt objektumra. Ebben az esetben minden objektumnak van egy prototípusa (Prototype). Amikor az objektum egyik tulajdonságához szeretnénk hozzáférni, akkor a futtató motor legelőször megkeresi az objektum saját tulajdonságai között. Amennyiben itt nem találja a keresett tulajdonságot, akkor a futtató motor feljebb lép az úgynevezett prototípus láncon és itt is elkezdi a keresést a kívánt tulajdonság után. A prototípus láncon való lépkedés addig történik, ameddig el nem érünk a lánc végére, a null-hoz. A másik megközelítés szerint (az objektumok dinamikus jellegét kihasználva) egy objektumban a már meglévő adatokat és metódusokat egyszerűen átmásoljuk (érték vagy referencia szerint) egy másik objektumba.

Objektumok létrehozása


A JavaScriptben rengeteg előre definiált elem, amivel eddig találkozhattál valójában objektum (még a sztringek és számok). Az objektumokat összetett (másik nevén referencia) adattípusokként kezeljük. A JavaScript objektumokat arra használhatjuk, hogy koncepcionizálhassuk a valós világ dolgait. Az elemek definiálásának sorrendje nem számít. Minden az objektumba foglalt elem kulcs-érték pároknak feleltethető meg. Amikor objektumokat használunk, akkor azok nem mentődnek el változókban (mint egy primitív típus), hanem csak annak a memóriacíme. Magyarán szólva az objektumok a hivatkozásuk szerint másolódnak. Bármilyen érvényes adattípussal rendelkezhet, beleértve másik objektumot (még név nélküli függvény is lehet értéke a kulcsnak). Az objektum-orientált programozás során az objektumok egységbe zárják az adatokat (tulajdonságokat), valamint a hozzá tartozó függvényeket (metódusokat). Egy objektum függvéynei (metódusai) általában az objektumhoz tartozó adatokon végeznek műveleteket.

let z = {kulcs: 20};
let v = z;
z.kulcs = 10;

console.log(z);
// {kulcs: 10}
console.log(v);
// {kulcs: 10}

Az objektumok deklarálása történhet {} objektum literállal, blokkba foglalva annak tartalmát. Objektumot literál formában akkor érdemes létrehozni, amikor előre ismertek azon tulajdonságai és metódusai. Habár utólag is hozzáadhatunk, törölhetünk, vagy módosíthatunk meglévő tulajdonságokat és metódusokat. Szintaktikája szerint a kulcsot követően az = értékadás helyett :-el történik, azt követi az érték. A különálló kulcs-érték párokat ,-vel választjuk el. Az objektumokat hozzá lehet rendelni változókhoz, ennek a típusa értelemszerűen objektum típussá konvertálódik. Inicializáljunk egy objektumot literál formában és rendeljük hozzá egy változóhoz (kutya). Legyenek definiálja az eletkor, nev és fajta tulajdonságok.

var kutya = {
   nev: "Kántor",    
   fajta: "németjuhász",  
   eletkor: 8
};

Az eddigi tudásunkra hagyatkozva ha több kutya objektumot szeretnénk létrehozni literál segítségével, akkor minden egyes példánynál újra és újra kell definiálni ugyanazt az objektumot, ami megnöveli a kódsorok számát, ezáltal nehezebben tudjuk átlátni a teljes programot. Tekintsük át a lenti példát.

var kutya1 = {
   nev: "Kántor",    
   fajta: "németjuhász",  
   eletkor: 8
};

var kutya2 = {
   nev: "Miruku",    
   fajta: "border collie",  
   eletkor: 3
};

Objektumok kezelése


A lepéldányosított objektumok tulajdonságaihoz és metódusaihoz hozzá tudunk férni az úgynevezett pontjelzés (dot notation) módszerrel. Szintaxisa szerint a lepéldányosított objektum után pontot rakunk, utána szimplán odaírva a tulajdonság, vagy metódus nevét meghívhatjuk azt. Amennyiben a meghívott tulajdonság konkrét értékre mutat, az objektumhoz rendelt változó adattípusa a tulajdonság értékének adattípusára konvertálódik át. Egy másik lehetséges hozzáférési lehetőség a zárójel jelzés (bracket notation). Szintaxisa szerint először a példányosított objektum nevét írjuk, aztán zárójelbe a tulajdonság nevét '' közé szúrva. Ez a megközelítés dinamikus tulajdonság és metódus elérés (ha nem ismerjük előre) esetén különösen hasznosnak bizonyul. A tulajdonságokra hivatkozhatunk indexekkel is (hasonlóan a tömbök szintaxisához). A tulajdonságokra a deklarálási sorrendjükben hivatkozhatunk (0-tól kezde). Nemcsak lekérhetjuk a kulcsokhoz rendelt értékeket, hanem meg is változtathatjuk. Szintaxisa szerint meghívjuk az objektum egyik tulajdonságát és értékül adjuk az új értéket = értékadó operátorral.

var kutya1 = {
   nev: "Kántor",    
   fajta: "németjuhász",  
   eletkor: 8
};

console.log(kutya1.nev);
// "Kántor"
console.log(kutya1['fajta']);
//  "németjuhász"
console.log(kutya1[2]);
//  8
kutya1.eletkor = 6;
console.log(kutya1.eletkor);
//  6

Getter


A getter egy olyan hozzáférő függvény (accessor) amit általában egy tulajdonság értékének megváltoztatásához szoktuk használni. Bármilyen általunk létrejozott, vagy beépített objektum esetén tudunk definiálni gettert, ahol az utólagos metódus definiálásra engedélyünk van. A get kulcsszó összeköti egy objektum tulajdonságot egy függvénnyel. Amikor meghívjuk ezt a tulajdonságot, a hozzá társított függvény végrehajtódik. Szintaxisa szerint a get kulcsszót követi egy olyan függvény, melynek nem lehetnek paraméterei. Továbbá a get-hez nem társíthatunk egy olyan nevű függvényt, ami már definiálva van az objektumban metódusként, vagy tulajdonságként. A lenti példában literál formában definiáltunk egy objektumot (nev és fajta tulajdonságokkal, szoveg metódussal és masikszoveg getter-el), melyet a kutya1 változóhoz rendeltünk. Amíg szoveg-et metódusként (kutya1.szoveg()), addig a masikszoveg-et tulajdonságként (kutya1.masikszoveg) hívhatunk meg. Az eredmény ugyanaz, viszont a második megközelítés szintaktikailag némileg egyszerűbb.

var kutya1 = {
	nev: "Dobi",
	fajta: "Whippet",
	szoveg : function() { 
		return `${this.nev} fajtája ${this.fajta}.`;
    },
    get masikszoveg(){
		return `${this.nev} fajtája ${this.fajta}.`;
    }
};
console.log(kutya1.szoveg());
//  Dobi fajtája Whippet.
console.log(kutya1.masikszoveg);
//  Dobi fajtája Whippet.

Setter


A setter egy olyan hozzáférő függvény (accessor) amit általában egy tulajdonsághoz rendelt értékének megváltoztatásához szoktuk használni. Bármilyen általunk létrejozott, vagy beépített objektum esetén tudunk definiálni settert, ahol az utólagos metódus definiálásra engedélyünk van. A get kulcsszó összeköti egy objektum tulajdonságot egy függvénnyel. Amikor meghívjuk ezt a tulajdonságot, a hozzá társított függvény végrehajtódik. Szintaxisa szerint a set kulcsszót követi egy olyan függvény, mely egyetlen kötelező paraméterrel rendelkezik. Általában a paraméter helyére átadott érték lesz a tulajdonsághoz rendelt érték. Továbbá a set-hez nem társíthatunk egy olyan nevű függvényt, ami már definiálva van az objektumban metódusként, vagy tulajdonságként. A lenti példában literál formában definiáltunk egy objektumot (nev és fajta tulajdonságokkal, szoveg setter-el), melyet a kutya2 változóhoz rendeltünk.

var kutya2 = {
	nev: "Dali",
	fajta: "pumi",
	eletkor = 6;
	get szoveg(nyersszoveg) { 
		var szavak = nyersszoveg.toString().split(" ");
		this.nev = szavak[0] || "";
		this.fajta = szavak[2].slice(0, -1) || "";
    }
};
kutya2.nev = "Csülök";
kutya2.fajta = "német boxer";
console.log(kutya2);
kutya2.szoveg = "Csubi fajtája puli."
console.log(kutya2);
A konstruktor tulajdonság meghívása

Tulajdonságok/metódusok hozzáadása/törlése


A JavaScriptben a futási időben lehetőségünk adódik hozzáadni, illetve törölni tulajdonságokat. Vegyük példának azt az esetet, amikor egy olyan objektumnak adok egy új tulajdonságot, aminek vannak példányai, akkor azok is meg fogják kapni. Ezzel szemben az osztály alapú nyelveknél (például Java) ez nem kivitelezhető, magát az osztályt kell megváltoztatni.

Tulajdonságok/metódusok hozzáadása


Az objektumok kezelésénél megismert dot notation és bracket notation segítségével definiálhatunk a példányosított objektumunk számára új tulajdonságokat/metódusokat. A motor végigmegy a példány tulajdonságain/metódusain. Ha egyezés történik, akkor a régi érték felülíródik az újjal, másképpen létrejön az új tulajdonság/metódus. A lenti példában literál formában definiáltunk egy objektumot (nev, fajta és életkor tulajdonságokkal), melyet a kutya1 változóhoz rendeltünk. Ezt követően hozzáadtunk egy szoveg() metódust a dot notation szintaxissal, melyet meghívunk. Vizsgáljuk meg a lenti példát.


var kutya1 = {
   nev: "Apacs",    
   fajta: "beagle",  
   eletkor: 3
};

kutya1.szoveg = function () {
	console.log(`${this.nev} fajtája ${this.fajta}.`);
};

kutya1.szoveg();
//  Apacs fajtája beagle.

Tulajdonságok/metódusok törlése


Az objektumok kezelésénél megismert dot notation és bracket notation segítségével törölhetünk meglévő tulajdonságokat/metódusokat a delete operátor segítségével.

  • A törlés parancs végrehajtása után visszatér egy boolean értékkel (true ha sikeres volt a törlés, false ha sikertelen volt a törlés). Ha a törölni kívánt tulajdonság/metódus nem létezik, akkor true értékkel tér vissza.

  • Ha egy objektum példányának tulajdonságát/metódusát töröljük és máshol is deklarálva van (a prototípus láncon magasabb hiearchiában), akkor csak a példányból törlődik az adott tulajdonság/metódus, máshonnan ugyanúgy elérhető lesz. Viszont ha onnan töröljük az adott tulajdonságok/metódust, akkor ezentúl egyik példány sem fog rendelkezni vele.

  • Bármilyen tulajdonságot/metódust (vagy éppenséggel változót), amit var kulcsszóval deklaráltak, nem lehet törölni a globális, vagy függvény hatókörből.

  • Bármilyen tulajdonságot/metódust (vagy éppenséggel változót), amit let vagy const kulcsszóval deklaráltak, nem lehet törölni a saját hatóköréből, ahol definiálva van.

A lenti példában literál formában definiáltunk egy objektumot (nev, fajta és életkor tulajdonságokkal, szoveg() metódussal), melyet a kutya1 változóhoz rendeltünk. Ezt követően kitöröltük a delete kulcsszóval az eletkor tulajdonságot. Vizsgáljuk meg a lenti példát.


var kutya1 = {
   nev: "Apacs",    
   fajta: "beagle",  
   eletkor: 3,
   szoveg : function() { 
		return `${this.nev} fajtája ${this.fajta}.`;
	}
};

delete kutya1.eletkor;

Egységbe zárás


Az egységbe zárás a függvények és adatok csoportosításán felül azok elrejtését is jelenti a külvilágtól. Ez abból a szempontból fontos, hogy megelőzzük a nem kívánt kapcsolatokat és hogy megkönnyítse a kód értelmezését. Egy objektum metódusaihoz és tulajdonságaihoz anélkül férhetünk hozzá, hogy bármiféle információt szolgáltasson azok működéséről és funkcionalitásáról. Más szavakkal megfogalmazva egy objektum metódusai az objektumhoz tartozó tulajdonságain végeznek műveleteket és globálisan nem érhetőek el. Ha az objektum elrejti a tulajdonságait és csak bizonyos metódusokon keresztül férhet hozzá a külvilág, akkor az egységbe foglalás az absztrakciót (láthatóságot), illetve az információ elrejtésének erős formáját valósítja meg.

Absztraktció/láthatóság


Az egységbe zárás alfejeztnél azt tanultuk, hogy egy objektum példánya közvetlenül a saját tulajdonságait éri el és metódusai az objektumhoz tartozó tulajdonságain végeznek műveleteket. Az absztraktció az implementáció részleteinek az elrejtésének jelenti. A segítségével a legkevesebb adatot oszthatjuk meg az adott utasítás végrehajtásához és biztosítja, hogy csak bizonyos környezetben legyenek elérhetőek. Az absztraktció nélkül a kód további fenntarthatósága kerül veszélybe. Több különböző láthatósági szintet különböztethetünk meg, ezek közül a legismertebbek: private (privát), public (publikus), protected (védett). Programozási nyelvenként eltér, hogy mely szinteket valósítják meg és hogyan:

  • Az adott elem amit privátnak szánunk, kizárólag az aktuális osztályból érhető el (amiből származik az objektum).

  • Az adott elem amit védettnek (privilegizáltnak) szánunk, kizárólag az aktuális osztályból és példányaiból érhető el.

  • Az adott elem amit publikusnak szánunk, minden osztály számára elérhető.

ES6 osztályok


Az osztály nem egy objektum, hanem az objektumnak a másolata. Az osztályok speciális függvények. Függvényeket definiálhatunk függvény kifejezéssel és deklarációval. Az osztályokkal sincs ez másképp. JavaScriptben a függvények egyben objektumok is. Használhatjuk a class kulcsszót és az osztály megnevezését, mint az osztály egyik lehetséges definiálási formáját, végezetül {} blokkba foglaljuk annak tartalmát. Az osztály létrehozásának szintaxisa eddig hasonlít a Java-hoz. A színfalak mögött azonban továbbra is prototípus-alapokon nyugszik az öröklődés. Konvenció szerint az osztályok nevét nagy kezdőbetűvel írjuk. Mint korábban említettük, bármely objektumnak lehet inicializálni a tulajdonságait. Az osztály alapú nyelvekben egy elkülönített úgynevezett osztály definiciós részben adjuk meg az osztály metódusait. Itt adhatunk meg egy speciális függvényt (metódust), amit a példányok létrehozására használunk. Ez az úgynevezett konstruktor. Ebben az eljárásban adhatjuk meg a tulajdonságok (property-k) kezdőértékét, és hajhatjuk végre az egyéb létrehozáskor szükséges műveleteket. A new operátor ezen metódusok segítségével hoz létre példányokat. A JavaScript hasonló példát követ, csak nincs elkülönítve az osztálydefinició a konstruktortól. Helyette definiálni kell egy létrehozó függvényt, ami meghatározza a tulajdonságok kezdeti halmazát, és értékeit. Bármely JavaScript függvény lehet konstruktor. Emellett objektumokat létrehozhatunk implicit módon is, azaz nem kezdetben adjuk meg tulajdonságait, hanem már létrejöttük után. Mint már korábban említettük, JavaScript-ben hozzá lehet adni vagy törölni tulajdonságokat. Ha például egy olyan objektumnak adok egy új tulajdonságot, aminek vannak leszármazottai, azok is meg fogják kapni. Mindezen absztrakciók arra szolgálnak, hogy emberközelibbé tegyék a programozást és elkerülhessük a felesleges kódismétléseket. Nézzünk rá a lenti példára. A konstruktornak van egy bemeneti paramétere (nev), ezen belül a this kulcsszóval rámutatunk a Kutya osztály példányára, ezzel be tudjuk állítani a Kutya példányának nev tulajdonságát, melynek értékét a nev argumentum paramétertől várható. A lepesszam tulajdonság pedig minden egyes példányosítás alkalmával 0 értéket kap. A Kutya osztályt példányosítsuk le Buksi névvel a new példányosító kulcsszó (operátor) segítségével. Ekkor a konstruktor meghívódik, a Buksi sztring értékül adódik a nev tulajdonsagnak, végül a példány értékül adódik a buksi változónak.

class Kutya {
  constructor(nev) {
    this.nev = nev;
    this.lepesszam = 0;
  }
};

var buksi = new Kutya('Buksi');
console.log(buksi.nev); 
// Buksi

Az osztályunk repeotárjához most hozzáadjuk az úgynevezett gettereket és settereket. Szintaktikailag hasonlít az objektumoknál megszokott metódusok szintaktikájához, a különbséget köztük csupán annyi, hogy nem kell vesszővel elkülöníteni őket egymástól. A lepesszamnovel() metódus meghívásával 1-gyel növekszik a _lepesszam tulajdonság értéke. A getter neve utal a tulajdonságára - visszatér valamilyen értékkel (ebben az esetben egy tulajdonsághoz rendelt érték). A setter név szintén utal a tulajdonságára - beállít valamilyen értéket. Ha az egyik példány (buksi) lepesszamnovel metódusát meghívjuk, attól a kantor példány lepesszam változója változatlanul 0 marad. Tovább bonyolítva a dolgokat, megkülönböztetünk publikus (public kulcsszóval) és privát (private kulcsszóval) tulajdonságokat, melyek a konstruktorban vannak definiálva. Ezzel letilthatjuk azt, hogy kívülről befolyásolni lehessen az adott tulajdonsághoz rendelt értéket. A JavaScript szintaxisában ez csupán egy _ a tulajdonság elé írva.

class Kutya {
  constructor(nev) {
    this._nev = nev;
    this._lepesszam = 0;
  };

  get nev() {
    return this._nev;
  };

  get lepesszam() {
    return this._lepesszam;
  };

  lepesszamnovel() {
    this._lepesszam++;
  }
};

var buksi = new Kutya('Buksi');

var kantor = new Kutya('Kántor');

Ha az eddig megismert elveket alkalmazzuk a példányok elkészítéséhez, akkor minden egyes új dolog bevezetéséhez új osztályt kell definiálni (ami lehet akár Macska is) és megint ott tartunk, hogy a kódunk egy csomó helyet foglal. Erre azt a megoldást találták ki, hogy magukat az osztályokat is lehessen többszörözni úgy, hogy definiálnak egy úgynevezett szülő osztályt (ez esetben Allat), a példányai (gyerek osztály) pedig öröklik a szülő osztály valamely tulajdonságait és metódusait (attól függően, hogy melyikre van szükségünk).

Öröklődés
class Allat {
  constructor(nev) {
    this._nev = nev;
    this._lepesszam = 0;
  };

  get nev() {
    return this._nev;
  };

  get lepesszam() {
    return this._lepesszam;
  };   

  lepesszamnovel() {
    this._lepesszam++;
  };
  
};

class Macska {
  constructor(nev, masiktulajdonsag) {
    this._nev = nev;
    this._masiktulajdonsag = masiktulajdonsag;
	this._lepesszam = 0;
  };

  get nev() {
    return this._nev;
  };

  get masiktulajdonsagmetodus() {
    return this._masiktulajdonsagmetodus;
  };
  
  lepesszamnovel() {
    this._lepesszam++;
  };
} 

Az öröklődés menete szintaktikailag a következő: definiáljuk a Gyerek osztálynevet, írjuk mellé az extends kulcsszót utána pedig a Szulo osztálynevet. Az örökíteni kívánt tulajdonságokat a konstruktorban a super(tulajdonsag1, tulajdonsag2, ...) speciális "metódus" meghívásával tehetjuk meg, az argumentumába pedig a kívánt paramétereket írjuk be. Ez tulajdonképpen meghívja a szülő osztály konstruktorát. Amennyiben új tulajdonságot akarunk definiálni (ami nem része a szülő osztálynak), azt a konstruktorban tehetjük meg ugyanúgy, ahogy eddig megszoktuk. Így már létrehozhatunk Macska osztályt is anélkül, hogy belegabalyodnánk a saját kódunkba.

class Macska extends Allat {
  constructor(nev, masiktulajdonsag) {
    super(nev);
    this._masiktulajdonsag = masiktulajdonsag;
  };
  
  get masiktulajdonsagmetodus() {
    return this._masiktulajdonsag;
  };
}

var cirmos = new Macska('Cirmi', false);
console.log(cirmos._nev);  
//  Cirmi

Néha előfordulhat az az eset, amikor olyan metódusokat szeretnénk generálni a Szülő osztályban, amiket nem szeretnénk, hogy örököljenek a Gyerek osztályai. Ilyenkor statikus osztályokat kell generálni a static kulcsszó segítségével (szintaktikailag a metódus neve elé kell írni a static kulcsszót).

class Allat {
  constructor(nev) {
    this._nev = nev;
    this._lepesszam = 0;
  };

  static nevgeneral() {
    const nevek = ['Morzsi', 'Pötyi', 'Fulonc', 'Miruku', 'Rudolf'];
    const randomszam = Math.floor(Math.random()*5);
    return nevek[randomszam];
  }
  
}

console.log(Allat.nevgeneral());  
//  visszatér egy random névvel

var morzsi = new Allat('Morzsi'); 
morzsi.nevgeneral();  
//  TypeError

Irodalomjegyzék

[1]
Vue.js core team. Vue.js: The Progressive JavaScript Framework. https://vuejs.org, Legutóbb megtekintve: 2019. április 22.
[2]
Vue.js core team. API, Global Config, directive. https://vuex.vuejs.org/vuex.png, Legutóbb megtekintve: 2019. április 22.
[3]
Vue.js core team. API, Global Config, computed. https://vuejs.org/v2/api/#computed, Legutóbb megtekintve: 2019. április 22.
[4]
Vue.js core team. API, Global Config, components. https://vuejs.org/v2/api/#components, Legutóbb megtekintve: 2019. április 22.
[5]
Vue.js core team. Vue-CLI. https://cli.vuejs.org/guide/creating-a-project.html#vue-create, Legutóbb megtekintve: 2019. április 22.
[6]
Vue.js core team. Vue-router. https://router.vuejs.org/guide/#html, Legutóbb megtekintve: 2019. április 22.
[7]
Vue.js core team. Render Functions and JSX. https://vuejs.org/v2/guide/render-function.html, Legutóbb megtekintve: 2019. április 22.
[8]
w3schools core team. JavaScript RegExp Reference. https://www.w3schools.com/jsref/jsref_obj_regexp.asp, Legutóbb megtekintve: 2019. április 22.
[9]
Google Chrome DevTools core team. Chrome DevTools. https://developers.google.com/web/tools/chrome-devtools, Legutóbb megtekintve: 2019. április 22.
[10]
Node.js core team. Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. https://nodejs.org/en/, Legutóbb megtekintve: 2019. április 22.
[11]
NPMJS core team. NPMJS. https://www.npmjs.com, Legutóbb megtekintve: 2019. április 22.
[12]
ExpressJS core team. Express Fast, unopinionated, minimalist web framework for Node.js. https://expressjs.com, Legutóbb megtekintve: 2019. április 22.
[13]
EJS core team. EJS: Embedded JavaScript templating. https://ejs.co, Legutóbb megtekintve: 2019. április 22.
[14]
Olga Filipova. Learning Vue.js 2. Packt Publishing Ltd., Livery Place, 35 Livery Street, Birmingham, B3 2PB, UK, 3, 2016.
[15]
E.F. Codd. A relational Model of Data for Large Shared Data Banks. Communications of the ACM, 13 (6) 1970.
[16]
Papp Edit. Adatbáziskezelés. Booklands 2000 Könyvkiadó Kft., 5600 Békéscsaba, Dr. Becsey Oszkár u. 42., 1, 2004.
[17]
Nemzeti Szakképzési és Felnőttképzési hivatal. Szoftverfejlesztő tanfolyam. https://www.nive.hu, Legutóbb megtekintve: 2019. április 22.
[18]
JavaScript.info core team. JavaScript.info. https://javascript.info/promise-basics, Legutóbb megtekintve: 2019. április 22.
[19]
Craig Buckler. Sitepoint (JavaScript) - Understanding ES6 Modules. https://www.sitepoint.com/understanding-es6-modules/, Legutóbb megtekintve: 2019. április 22.