Az alábbiakban rengeteg jegyzetet felhalmoztam a témában, amiket szándékomban áll jelentősen rendszerezni a közeljövőben.
Bevezetés
A JavaScript 1995-ben, az akkor a Netscape-nél mérnökként dolgozó Brendan Eich alkotásaként indult hosszú, hódító útjára. Ennek megfelelően elsőként a korszak meghatározó jelentőségű webböngészőjében, a Netscape Navigatorban jelent meg a nyelv támogatása, méghozzá rögtön 1996 elején, a program 2.0-s verziójában. Eredetileg Mocha-nak, kicsit később LiveScript-nek nevezték volna, de mivel akkoriban a Netscape épp szoros üzleti kapcsolatban állt a Java-t birtokló Sunnal, egy meglehetősen elhibázott marketing-döntés nyomán úgy vélték, hogy az akkor már egészen sikeres Java népszerűségét meglovagolják, és végül a nyelv a JavaScript nevet kapta. Neveik alapján arra számíthatnánk, hogy a két nyelvben számos párhuzamra kellene akadnunk, ám valójában azok csak kis mértékben hasonlítanak. Valóban voltak a fejlesztés első, sürgetett kezdeti szakaszában a Netscape-nél olyan felsőbb szintű igények, hogy a nyelv hasonlítson a Java-hoz, de ez ezen a szinten meg is állt. A programozási nyelv neve még napjainkban is rengeteg félreértést szül, így aztán a kissé fura névválasztás tekintetében a rövid és tömör összefoglaló:
A két programozási nyelvnek semmi köze sincs egymáshoz.
Az erről szóló legelterjedtebb mondás a "Java is to JavaScript what Car is to Carpet.", amelynek magyar megfelelője akár így is szólhatna: "A Java-nak annyi köze van a JavaScript-hez, mint a rókának a parókához" (eredetileg autónak a szőnyeghez).
Megjelenését követően néhány hónappal később a Microsoft is beépítette saját JavaScript megvalósítását, a JScript-et az Internet Explorer 3-ba, majd újabb hónapok elteltével a Netscape a JavaScript szabványosítását elősegítendő, elküldte azt az ECMA International-nak (European Computer Manufacturers Association) és még 1997 júniusában megjelent az ECMAScript szabvány első kiadása. A szabványon tovább dolgoztak, és az első kiadást pontosan egy évvel követte a második, az ISO/IEC 16262 nemzetközi szabvánnyal való összhang megerősítése érdekében.
A szabvány 1999 decemberében, a 3. kiadásában érte el első igazán jelentős mérföldkövét, és attól kezdve tekinthetjük a nyelvet igazán stabilnak, megbízhatónak.
A 4. verzió soha sem érte meg a végleges kiadását számos eltúlzott újítása, összetettsége miatt, így 2008-ban végleg elhagyatottnak (abandoned) nyilvánították.
Az 5. verzió 2009 decemberében jelent meg olyan fontos újításokkal, mint a foreach
, a map
és a filter
. 2015 júniusában jelent meg az azóta is leginkább meghatározó ECMAScript 6. Újítása azóta is meghatározóak és széles körben alkalmazottak. A legismertebbek ezek közül a let
, a const
, a for...of
ciklus, a Python-stílusú generátorok, a függvények innentől kezdve alapértelmezett paramétereket is kaphatnak és egy egészen új módon, az arrow function expression módszerrel (() => {...}
) is definiálhatóak.
A 2016-os 7. kiadás nem hozott jelentős újdonságokat, ám a 2017-ben megjelent ECMAScript 8-ban a nyelv újabb fejlesztéseket kapott elsősorban a párhuzamosan futtatható programszálak területén az Async függvények és a Shared memory and atomics bevezetésével.
A fentiek alapján kijelenthető-e akár az is, hogy a továbbiakban ECMAScript programozásról fogunk olvasni, abban fogunk programozni? A kérdésnek van alapja, hiszen eredetileg az ECMAScript főleg a JavaScript-ből vált szabvánnyá, majd onnantól kezdve a JavaScript az ECMAScript szabványa szerint fejlődik, mégis az egyik csak egy szabvány, míg a másik a szabványból származó programozási nyelvi megvalósítás. Ugyanez az ECMAScript a közös szabványa a JScript, ActionScript, TypeScript stb. nyelveknek is, azonban a JavaScript az ECMAScript kétségkívül legnépszerűbb implementációja. A helyes megfogalmazás tehát valahogy így hangzik: a továbbiakban az ECMAScript 8 alapú JavaScript programozással fogunk foglalkozni.
Néhány hasznos olvasmány a JavaScript történetét illetően:
- JavaScript is dead - long live… ECMAScript!?
- A re-introduction to JavaScript (JS tutorial)
- Noobs Guide: Javascript vs JQuery vs ECMAScript vs Typescript
- JavaScript: What the heck is a Callback?
Mint látható, a JavaScript folyamatosan fejlődik, de még nagyobb változás (és őszintén szólva valódi káosz) figyelhető meg a hozzá kapcsolódó kiegészítők, modulok tekintetében. Ami ma még a legjobb módszer egy webes technika megvalósítására, könnyen előfordulhat, hogy 2-3 év múlva már annak megemlítése is ciki az igazán keményvonalas fejlesztők körében. Íme egy kis olvasnivaló ebben a témában is:
A fejlesztési környezet kialakítása, alapfogalmak
A tanulás során, illetve féldinamikus weboldalak készítésekor a legjobb fejlesztési környezetet maga a webböngésző nyújtja. Ennek igénybevételéhez használhatjuk a webböngésző Developer Tools (Firefox-ban: [F12]) → Console funkcióját (ugyanennek elérése Firefox-ban rögtön a [Ctrl]+[Shift]+[K] billetyűkombinációval is lehetséges).
A fejlesztéshez a VSCode a leginkább ajánlott szerkesztő, amelynek rövid bemutatása itt található.
2.1 Alapfogalmak
Mindenek előtt meg kell ismerkednünk annak a módjával, ahogy a tanulás során a programjainkat működésre bírjuk. Ez lehetőleg kényelmes, gyors és áttekinthető kell legyen, minimális kattintgatással.
2.1.1 Variációk a "Hello világ!" programra
Az elmaradhatatlan fejezet következik rögtön négy megoldással, amelyek közül egyelőre maradjunk a legutolsónál, de mindenképpen próbáljuk ki mindegyiket legalább egyszer.
A lenti programok alapja a program futásakor mindenképpen létrejövő console
objeketum log()
metódusának használata, amely az objektumorientált programozási paradigmának megfelelően a legelterjedtebb módon, egy pont karakterrel illeszthető egybe:
2.1.1.1 A webböngésző konzoljával, HTML kódba illesztve
Készítsünk egy index.html
nevű állományt az alábbi tartalommal:
Ha kész, nyissuk meg egy webböngészőben, és az előző fejezetben már említett módon tekintsük meg az oldal által generált konzolkimenetet.
2.1.1.2 A webböngésző konzoljával, külön .js fájlban elhelyezve
Az előzőhöz nagyon hasonló index.html
állomány csak hivatkozást tartalmazzon a beillesztett JavaScript fájlra:
A hivatkozott test.js
állomány tartalma (ugyanabban a könyvtárban, ahol az index.html
is található):
console.log("Hello világ!");
2.2 Programírási szabályok
-
A JavaScript kis-/nagybetű-érzékeny ("case sensitive"), tehát a
futtat
, aFuttat
és aFUTTAT
három különböző dolgot jelenthet. Erre különösen figyeljünk, éppen ezért -
Használjunk a camelCase névadási módszert:
- a változók neve kezdődjön kisbetűvel (pl.
greenDuck
) - az objektumok és osztályok nevei nagybetűvel induljanak (pl.
Duck()
) - a konstansok neve lehetőleg csupa nagybetűs legyen (pl.
DUCKCOLOR
)
- a változók neve kezdődjön kisbetűvel (pl.
-
A szóközök, behúzások, sorközök rengeteget számítanak! A JavaScript kód sorközök és további szóközök nélkül is működőképes, de az olvashatóság miatt rendkívül fontos a szabályos tagoltság.
-
Az összetartozó kódsorok végén pontosvesszőt kell tennünk. Általában szükségtelenek a kód futtathatóságának szempontjából, de ismét csak az áttekinthetőség miatt erősen ajánlottak.
-
Ahol csak szükségét érezzük, alkalmazzunk kommenteket:
Deklaráció, adattípusok, struktúrák és kifejezések
A JavaScript-ben a konstansok és változók típusa dinamikus, azaz létrejöttükkor kerül megállapításra a típusuk.
3.1 Konstansok
Nevükből is kikövetkeztethető: a konstansok értéke a program futása során nem változhat. Definiálása a const
utasítás után történik const
KONSTANSNÉV = tartalom;
szintaktikával. Két ugyanolyan nevű konstanst vagy változót nem adhatunk meg, hiszen akkor nem tudnánk a megfelelőre hivatkozni. Miután definiáltunk egy konstanst, a fordító a továbbiakban ezzel a konstansnévvel találkozva már a fordítás alatt annak értékét írja a helyére.
Ennek az eredménye a böngésző Web Console ablakában:
Akár a konstansok, akár a változók esetében a .log
mellett a .dir
metódus is használható, amely igazán látványos kimenetet majd az objektumok esetében fog megjeleníteni. Példaprogramunkat egy további hasznos függvénnyel, a typeof
-al is kiegészíthetjük, amely a konstans vagy változó típusával tér vissza.
3.2 Változók
A var
kifejezéssel egy változót deklarálhatunk, illetve opcionálisan rögtön hozzárendelhetjük azt egy értékhez.
A let
kifejezéssel egy block scope-on belüli, helyi változót deklarálhatunk, amely szintén akár már létrehozáskor megkaphat egy értéket is.
E kettő közül az utóbbi években egyértelműen a let
vált a gyakoribbá, mivel logikusabb.
Az alábbi két program közül az első esetben még az x
változó deklarálása előtti próbálkozás is ad valamiféle eredményt ("undefined"), míg a másodiknál erre esélyt sem kapunk a fordítótól. Ezt nevezzük "Hoisting"-nek.
- Hoisting
var
-al:
- Hoisting-el való próbálkozás
let
-el:
3.3 Tömbök
…
3.4 Kifejezések
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/ExpressionsandOperators
A kifejezések kétféle összetevőből állnak: operátorokból és azok operandusaiból. Az operátorok tulajdonképpen a műveletek, az operandusok, pedig a számok, értékek, melyekkel a műveleteket végezzük.
Nézzünk egy tipikus példát, ahol az egyik értéket összehasonlítjuk a másik értékkel:
Ebben a kifejezésben azt vizsgáljuk, hogy az a
nagyobb-e b
operandusnál. A nagyobb jelet ábrázoló kacsacsőr egy relációs típusú operátor. A bináris operátorok közé is csoportosíthatjuk, ami azt jelenti, hogy két operandus tartozik hozzá. A legtöbb operátor bináris.
3.4.1 Értékadó operátorok
Erre való a =
karakter. Pl.:
3.4.2 Aritmetikai operátorok
Alapvető számolási műveleteket végezhetünk velük egész vagy valós típusú számokkal. Ezek a következők lehetnek:
+
összeadás-
kivonás*
szorzás/
osztás%
osztás maradékképzése++
növelés--
csökkentés**
hatványozás
Az aritmetikai operátorokhoz tartozik még továbbá két "unáris" operátor a +
és a -
előjel.
3.4.3 Logikai operátorok
Logikai (boolean) műveleteket végeznek el logikai típusú operandusok között logikai típusú eredményt hozva. Egyszerű logikai kifejezések, valamint több más típusú kifejezés összekapcsolásával összetett logikai kifejezések alakíthatók ki velük.
Az alábbiak tartoznak ebbe a csoportba:
&&
logikai és||
logikai vagy!
logikai tagadás
3.4.4 Relációs operátorok
Egész és valós típusú operandusok között végezhetünk velük vizsgálatokat:
==
egyenlő!=
nem egyenlő===
szigorúan egyenlő (tartalomra és típusra egyaránt)!==
szigorúan nem egyenlő (tartalomra és típusra egyaránt)<
kisebb, mint…>
nagyobb, mint…<=
kisebb-egyenlő, mint…>=
nagyobb-egyenlő, mint…in
egyik elemee a másiknak
Figyelem: a =>
nem operátor, hanem az újabb típusú függvényjelölés (Arrow function notation).
3.4.5 Szövegösszefűző operátor
Egymástól elkülönített szövegeket, vagy egy változó ill. konstansnév utáni szöveget a +
operátorral tudunk kiíratáskor összefüggővé tenni az alábbi módokon:
Sőt, akár még így is használható:
További operátorok és részletes ismertető: developer.mozilla.org/…/Expressions_and_Operators
(+1: A Math.floor()
függvény egy decimális értéket generál.)
Vezérlési szerkezetek
…
4.1 Elágazások
4.1.1 Egy és kétirányú elágazás
if
if...else
4.1.2 Többirányú elágazás
switch
4.2 Ciklusok
while
4.2.1 A A JavaScript és sok más programozási nyelv esetében ez a tipikus elöltesztelős ciklus. A programblokk futásának előfeltétele, hogy kifejezés igaz értéket vegyen fel. Amennyiben ez már induláskor sem teljesül, a ciklus egyszer sem fut le. Amennyiben teljesül, a ciklusmag újra és újra futtatásra kerül egészen addig, amíg még igaz a bemeneti vizsgálat eredménye:
A következő programblokkban arra láthatunk példát, hogy a ciklus egyszer sem fut le, hiszen már az előzetes vizsgálat során is hamis eredményt kapunk (n
kisebb 2-nél):
do...while
4.2.2 A A JavaScript a do...while
módszerrel valósítja meg a hátultesztelős ciklust. Mint látható, a programblokk legalább egyszer lefuttatásra kerül, majd csak ezután vizsgálja meg az összefüggést. Más szavakkal: addig futtatja a programblokkot, amíg az összefüggés hamis értéket nem kap:
Jól megfigyelhető, ahogy a korábbi while
ciklussal teljesen megegyező do...while
-os átirata egyszer megnövelte az n
változó értékét.
for
4.2.3 A Minden programozási nyelvben a for
-nak valamilyen változatával alkothatunk meg növekményes ciklusokat. Ennél a típusnál elsősorban nem összefüggések kiértékelésétől függ a ciklusmag futása, hanem nagyon leegyszerűsítve, tulajdonképpen saját magunkat kíméljük meg felesleges kódsorok bepötyögésétől.
A for
alapmodelljében három paraméter, a bemeneti átmeneti változó (amelyet az "index" mivolta miatt gyakran i
-nek nevezünk), az előtesztelés és az átmeneti változó növelése segíti a növekményes ciklust:
for...in
4.2.4 A A for...in
használata az alapmodellnél már sokkal életszerűbb, ugyanis előszeretettel használjuk egy szöveges beérkező adatfolyam "körbejárásához". Íme egy példa erre:
for...of
4.2.5 A A for...of
az előbbi továbbgondolt változata, amely a későbbiek során megismert JSON adathalmazok körbejárását segíti elő. Olyan adattípusokat támogat csak, amik "iterálhatóak". A tömbbe illesztett objektumok ilyenek:
for await...of
4.2.6 A Async és sync iterálható objektumok körbejárásához alkalmazható növekményes ciklusokat írhatunk a segítségével.
A szintaxisa:
Használatára majd csak a későbbiekben, a Promise-ok és az async/await függvények alkalmazásakor térünk ki.
4.3 Megszakítások
break
4.3.1 A continue
4.3.2 A try...catch
4.3.3 A …
További vezérlési szerkezetek és részletes ismertető: developer.mozilla.org/…/Statements
Függvények
Az összetartozó, különösképpen a többször is felhasználni kívánt kódsorokat egy külön kódblokkba érdemes helyeznünk.
…
A függvények elnevezésének szabályai azonosak a változónevek szabályaival:
- akár a
$
,_
,a..z
,0..9
karakterek bármelyikét, sőt, még különféle speciális karaktereket is tartalmazhat - számmal nem kezdődhet
- nem lehetnek már létező parancsszavak (pl.
for
,while
stb.)
Függvénynevek megalkotására a https://mothereff.in/js-variables weboldal is segítségünkre lehet.
A függvények meghívásának a JavaScript-ben több módja is lehetséges:
- Hagyományos (Named) függvénydeklaráció
- Névtelen (Anonymous) függvénydeklaráció
- Azonnal meghívott függvénykifejezés (Immediately invoked function expression)
- Magasabb rendű (Callback) függvénydeklaráció
A this
attribútum az objektum adott instance-ának értékét kapja meg (arra mutat).
5.1 Hagyományos függvénydeklaráció
5.2 Anonymous függvénydeklaráció
5.3 Azonnal meghívott függvénykifejezés
5.4 A callback függvény
5.5 A "call-and-apply" függvénymeghívás
A "return" function statement nagyjából opcionális. Visszatérési értéke egy kifejezés. Ha nincs ott, hogy mi lesz a visszatérési érték, akkor is lesz legfeljebb egy "undefined".
Anonymous függvénynek tekintjük ezt azért, mert a function
kulcsó után nem határozunk meg nevet.
Függvénydeklaráció függvény-kifejezéssé alakítására is gyors megoldást kapunk. Magától meghívhatóvá tehetjük ezzel a függvényt:
Ez így nem hívódik meg:
Így viszont már igen, ezt hívjuk "closure"-nek:
Ugyanez argumentum megadásával:
A "scope" (hatókör) egy változó életét és halálát jelenti.
Itt a "dogName" változó a meghívásakor a "Morzsi" értéket kapja:
A globális változó definiálása erősen kerülendő dolog:
A hoisting az az, amikor előbb van a változóra hivatkozás, mint a változó definiálása, de a JS mégis tudja, hogy van valami, így "undefined" értéket kap:
A modulok készítése esetén érdemes a namespacing-el is törődni: "Namespacing allows you to protect any variables that you have in your modules from any global scoped variables."
A "return" statement nagyon hasznos akár objektumok visszatérési értékként való elküldésére.
Itt, ebben a nagyon egyszerű modulban gondosan elszeparáltuk (megvédtük) a változót a külső scope-tól:
…másik <script>
tag-en belül meghívva:
Argumentum küldése egy függvénybe (itt csak az a veszély, ha nincs argumentum):
Az előző továbbfejlesztése, hogy legyen egy default érték:
Az előzőnél elegánsabb megoldás, ha a függvény elején a DEFAULTS
értékeket definiáljuk:
A "Chaining" azt használja ki, amikor a "return this;" sor az objektum adott instance-ával tér vissza.
A HTML kódban az előzőt így hívjuk meg:
Osztályok
6.1 A függvények és osztályok közötti különbségek
A függvények hoist-elhetőek, az osztályok nem, tehát mindenképpen előbb kell deklarálni az osztályt, mielőtt használnánk. A függvényeket felül lehet írni, az osztályokat nem. Az osztályoknak is lehet metódusokat adni, melyeket ugyanúgy újra fel lehet használni.
6.2 Strict mode
ES5-ben lett bemutatva. Olyan error-okat is kaphatunk a használatával, amikhez régen nem férhettünk hozzá. A még nem széles körben elfogadott szintaxisok használatát szándékosan tiltja. A MDN-en többet is meg lehet tudni róla.
6.3 Statikus metódusok
Static methods are methods that aren't accessible through an instance of a class, but only available through the class itself. They are usually created for utility functions that don't relate to the instance of the class. I rarely need to use static methods, but when I do, it's always good to be aware they exist.
Az eredmény a böngésző konzoljában:
6.4 Prototípus metódusok
A konzolban található <prototype>: Object { … }
fát kibontva láthatjuk az objektum konstruktorát, a constructor: function Car()
-t. Itt megláthatjuk mindazt a konstruktort, amit használhatunk a Car
osztályú objektumhoz, pl. a Car.doors
-t. Ugyanitt a prototype
részben az alkalmazható metódusokat is listázva láthatjuk:
6.5 Konstruktorok
Constructors are part of the syntax of a class. If you don't include one, one will be generated for you. Also you can only do one constructor per class, otherwise there will be a syntax error thrown at you. A konstruktor tehát automatikusan készít egy objektumot számunkra. A super
kulcsszó lehetővé teszi a szülő osztály metódumainak meghívását.
Az extends
kulcsszó tehát kiterjeszti a már meglévő osztályt, amiből öröklődik.
Amennyiben egynél több osztályt szeretnénk kiterjeszteni egy újabb osztályhoz, a mixin a megoldás. Ilyenkor nem öröklődés történik, hanem összeállítás. Csak nagy óvatosággal használjuk!
Aszinkron programozási alapok
Amikor egymás után állunk sorban mozijegyet venni, az egy szinkron folyamat. Valakinek tovább tart, valakinek rövidebb időt vesz igénybe, de szépen sorban egymás után kivárjuk. Miközben várunk, a mi folyamatunk szempontjából blokkolás zajlik. Az időigényesebb kiszolgálási idővel járó feladatok teljesítése méghosszabb blokkolási idővel jár, így ekkor már valóban szükség van aszinkron kiszolgálásra. Egy másik, mindennapi életből merített példával élve így történik egy étteremben, több pincérrel.
Amikor csak lehet, tehát amikor az egyik folyamat végrehajtása nem függ egy másik, hosszabb időt igénybe vevő folyamat eredményétől, aszinkron programfolyamot érdemes használnunk.
Három eszköz is rendelkezésünkre áll aszinkron programrészek futtatására, amennyiben annak eredménye szükséges más programrészek futásához:
- callback függvény
- promise
- async/await alkalmazása
7.1 Callback
Időnként szükségünk lehet arra, hogy további függvényeket vagy metódusokat futtassunk, miután egy aszinkron függvény végrehajtódott. Hagyományosan ezt "callback" igénybevételével tudjuk elérni, ami lehetővé teszi, hogy egy aszinkron függvény meghívása egyszerre (párhuzamosan) úgy mehessen végbe, hogy a főprogram folyamata sem áll le, addig sem blokkolódik. Ez az aszinkron függvény argumentumként kell, hogy használjon egy másik függvényt. Miután az eredeti függvény összefüggései végrehajtódtak, a függvény maga adódik át egy meghívott argumentumként. Az így meghívott függvényt hívjuk callback függvénynek. A callback lehetővé teszi számunkra, hogy mi történjen egy aszinkron módon futó függvény lefutását követően.
A setTimeout függvény például két argumentummal kell rendelkezzen: egy callback függvénnyel és egy időintervallummal:
Az alábbi kódban tehát a szinkron kód eredménye előbb kiíródik, hiába található meg a kódban később:
Az aszinkron függvény végzi tehát a várhatóan időbe telő kérést és egy callback-et az eredményül kapott adattal…
A success
is egy ilyen callback. Ha pedig arra is kell számítanunk, hogy az időbe telő függvény hibára fut, akkor "fail callback"-et is be kell építenünk.
Amikor többszörösen láncolt callback-eket alkalmazunk, könnyen köthetünk ki egy "callback hell" nevű kódsornál, ami nehezen áttekinthető. Erre nyújt megoldást a promise.
7.2 Promise
A promise (ahogy az elnevezése is sugallja: ígéret) információt ad egy műveletről és nyomon követi annak állapotát.
Rendelkezik egy state
property-vel, ami lehet pending
, fulfilled
vagy rejected
, valamint egy result
property-vel, ami induláskor még undefined
értéket kap, de siker esetén végül megkapja a művelet eredményét. Ez alapján tehát a pending
állapotban (state
) a result
értéke undefined
, a fulfilled
állapotban az érték a feldolgozás eredményeként született érték, a rejected
állapotban pedig egy hibaleírás (error
).
Először egy új promise-t hozunk létre a Promise
konstruktorral…
Mivel a JS kódjában a szóközök nem számítanak, új sorokban felsorolhatjuk egymás után a .then
(és egyéb) blokkokat.
A .catch
metódussal az error-t tudjuk lekezelni, amit az eredeti promise generált hiba esetén.
A .finally
metódussal azokat az utasításokat hajthatjuk végre, amik függetlenek attól, hogy a promise eredménye sikeres vagy elutasított lett.
A Promise.all
metódussal minden promise-t összevonhatunk egy tömbbe.
7.3 Async/Await
Bár már a promise-ek is nagy előrelépést jelentenek a callback-ekhez képest, még mindig nehezen követhetőek. Emiatt az async/await a legolvashatóbb módszer aszinkron függvényekhez. Az async/await kód a háttérben promise-ek használatával füt le egyébként, tehát ez csak minket, programozókat segít. A kód a Babel igénybevételével akár ES6 előtti kódsorrá is képes alakítani kodunkat, vagy annak egy részét.
Kicsit valósabb példa try
és catch
blokkokkal kiegészítve:
Példaprogram egy Promise
-t, async
-et és await
-et felhasznáva:
Itt is ugyanúgy használható a végén mindenképpen végrehajtódó finally
blokk is.
Csak async
és await
felhasználásával és egy időigényesebb számítást beépítve szemléletesebb példaprogramot hozhatunk létre:
...bár ez még így is megfelelő sorrendben írja az üzeneteket, úgyhogy ezen még dolgozom:
JSON
8.1 Általános tudnivalók a JSON-ról
A JavaScript Object Notation rövidítése.
A JS objektumkezelési szintaktikáján alapul (de nem pontosan ugyanaz!), így sokkal hatékonyabb JavaScript app-okkal, mint a nehezebben kezelhető XML. Mostanra már számos más nyelv kiválóan kezeli a JSON-t (Python, C++ stb.).
A különbségek és szabályok a JS objektumleírásokhoz képest:
- a kulcsok és értékek egyaránt dupla ("rendes") idézőjelek között kell, hogy legyenek. Az aposztróf sem elegendő, a kulcsoknál az idézőjelek elhagyása szintén nem elfogadható.
- a kulcsokban is lehet szóköz és mindenféle karakter, de ezek nagyban nehezíthetik a kezelést. Az aláhúzás OK.
- csak e 6 adattípus valamelyike lehet az érték: string, number, object, array, boolean vagy "null"
- a JS objektumban egy kulcs értéke akármilyen típus lehet, akár egy függvény is (és ez gyakori is egyébként)
- a JSON megetetése a JS-el csak "parse"-olást követően történhet (
eval
vagy .parse
). A folyamat ellenkezője astringify
metódussal történik. (JS objektum konvertálása JSON adattá)
Az utolsó érték után nem kell vessző:
Lehet szépíteni is a jobb olvashatóság kedvéért:
Hozzáférés egy értékhez (dot notation):
Ugyanez bracket notation-el (ha a kulcs érvénytelen lenne JS esetében, pl. ha a kulcsban szóköz van):
Objektum értékként való használata:
Bár az elérés egyszerűbb, nincs rá garancia, hogy az objektum elemei az eredeti sorrendben tárolódnak a memóriában is. Emiatt a tömb használata esetenként ésszerűbb.
Tömb értékként való használata: ennek a megadási módja szintén szögletes-zárójelek között történik:
Az utolsó érték egyikének elérése így:
A JSON-t érdemes validáltatni valamilyen tool-al, amilyen pl. a JS Hint (JS validálás) vagy JSONLint (csak JSON validálás). Még ezeknél is látványosabb a JSON Editor Online (jsoneditoronline.org). A böngésző is tudja a JSON-t megfelelően megjeleníteni.
A módosítás is a sima dot notation-el hozzáférhetően módosítható, vagy akár törölhető, pl. delete(info.title)
.
A tömbből elem törlése, hozzáadása viszont nem ilyen egyszerű, tehát pl. a delete(info.courses[1])
módszerrel nem lehet törölhetjük ki az 1. sorszámú elemet. Helyette a splice
és push
metódusokat kell használnunk:
Ha a tömbön belül objektumokat használunk, akkor azon is működnek a splice
és push
metódusok:
Tömbön belüli objektumos verizó (ami még mindig nem teljesen oké):
8.2 Objektum elemeinek ciklusba helyezése
8.2.1 Tömbön belüli objektumok elérése, ciklusba helyezése
A JSONP egy másik technika, hogy rendezett JSON adatokat töltsünk le külső weboldalakról. Pl.:
JSONP Request:
JSONP Response:
A jQuery is hasznos segédeszköz, ha .json adatfájlokat kell betöltenünk.
Egy letöltött JSON fájl általában emberi olvashatóságra nem alkalmas állapotban érkezik, azaz egyben van az egész sortörések és behúzások nélkül. Ezen segít a JSON.stringify
metódus:
In a modern browser, we can test if an object is empty using the Object.keys.length
property.
JSON Schema-t is definiálhatunk, amivel aztán validáltathatjuk a betöltött JSON adatot. Arra is jó, ha required property-ket akarunk vele követeltetni.
8.3 Konverziók
8.3.1 XML - JSON konverzió
Az XML esetében minden tag-nek bezárva kell lennie (akár />
végződéssel), az egésznek egy tag-ben kell lennie ("single root element"), az egymásba helyezett tag-eknek megfelelő sorrendben kell lenniük és még a kis-/nagybetűknek is stimmelniük kell.
A json2xml.js és a xml2json.js egyszerű library-k a kettő közötti konverzióra.
8.3.2 YAML - JSON konverzió
A YAML-t mégegyszerűbb ember számára olvasni még a JSON-nál is ("YAML is superset of JSON"), mert sortöréseken és behúzásokon alapul. A szövegekhez még idézőjelet sem kell alkalmazni. JS-ben nem is használható közvetlenül. A fájlok kiterjesztése a .yml
.
A yaml.js nyújt konverziót oda-vissza.
8.4 Függvény értékként való beszúrása
Ez csak egy próba, majd még lehet, hogy módosítom: (???)