Az Objektumok hierarchiája című oldalon azt célt fogalmaztuk meg,
hogy készítsünk egy olyan programot, ami a következőket tudja:
kilistázza a JavaScript legfelsőbb szintű objektumának, a window objektumnak az összes elemét
szétválogatja őket aszerint, hogy az adott elem objektum, függvény, vagy változó
a lista minden eleme egyben egy link is, ahol bármelyikre rákattintva eredményként láthatjuk a kiválasztott elem saját "gyerekeit"
és ez így folytatódik a lehetséges legnagyobb mélységig.
A program eredményeként azt szeretnénk átlátni, hogy miként szerveződnek hierarchikusan egymás alá
a JavaScript különböző elnevezésű objektumai - illetve hogy igaz-e az, hogy minden létező objektum
megtalálható a window objektum valamely gyermekeként, vagy annak gyermekeként, vagy annak
gyermekeként, vagy annak gyermekeként...
Ott, azon az oldalon, a már kész program felhasználásával vizsgáltuk a JavaScript objektumainak
hierarchiáját, és igazoltuk a fenti állítást. Ezen az oldalon viszont azt tekintjük át, miként is
lehet(ett) elkészíteni ezt a bizonyos programot.
1. Hogyan álljunk neki?
Első lépésként - a lehető legegyszerűbben és leggyorsabban - kellene írnunk egy olyan kódot,
ami ömlesztve kilistázza a window objektum elemeit! Ehhez a JavaScript
Object.getOwnPropertyNames
függvényét hívhatjuk segítségül, mely képes egy objektum saját tulajdonságelemeinek nevét
egy tömb elemeiben visszaadni.
A kapott tartalom kétségtelenül bíztató - csak éppen ebben a formában kezelhetetlen.
Szükségszerűnek tűnik például legalább azt megoldani, hogy a listázott elemek egymás
alatt, lehetőleg betűrendben jelenjenek meg.
2. Jelenítsük meg az elemeket egymás alatt, betűrendben!
A tömb elemeinek rendezéshez a
sort() függvényre,
az elemek egyesével történő megjelenítéséhez pedig egy ciklusra lesz szükségünk, mely a tömb
elemein szalad végig a sorszámuk szerint.
Alakul. De vajon hány elemet is látunk a listában?
3. Sorszámozzuk meg a lista elemeit!
A sorszámozás legegyszerűbb módja, ha kihasználjuk a HTML <ol>, illetve <li> tag-jeinek
lehetőségeit. Ez esetben akár az előző változatban szereplő sortöréseket is kihagyhatjuk, hiszen
a listázás eleve tartalmazza azt.
Amennyiben esetleg arra számítottunk, hogy a window objektumhoz nagyjából mindössze egy,
vagy legfeljebb néhány tucat saját elem köthető, akkor bizony az eredményként kapott
sokkal-sokkal több elem igencsak meglepetésre adhat okot. Pedig a dolog valóban így áll:
böngészőtől, és annak verziószámától függően a lista elemszáma akár az ezret is közelítheti,
vagy meghaladhatja.
Ám egyben a kérdés is felmerül: ezen rengeteg elem közül melyek lehetnek olyan objektumok,
amelyek szintén rendelkezhetnek további saját gyermekekkel. Ennek megállapításához látnunk
kellene az egyes elemek típusát is.
4. Jelenítsük meg a lista elemeinek típusát is!
Egy JavaScript változó típusa a
typeof
operátorral kérdezhető le. A probléma csak az, hogy ha
megkérdezzük egy-egy tömbbéli elem típusát, akkor az kivétel nélkül mindre azt fogja mondani, hogy
string, hiszen szöveg típusú változóként tároljuk el az elemek neveit. Éppen ezért mivel
tehát mi valójában a szövegekben tárolt elemnevek típusára vagyunk kíváncsiak, használnunk kell az
eval()
függvényt.
Így tehát bevezetve és kiiratva a tipus változót, már láthatjuk minden elemünk
típusát is. Ezek között az alábbi kifejezések fedezhetőek fel:
object
function
string
number
boolean
undefined
Az volna a jó, ha a programunk szétválogatná a listaelemeket 3 típusba:
először felsorolná az összes olyan gyermek elemet, ami ő maga is egy új objektum,
második kupacban listázná a függvényeket,
végül pedig jönne minden más, ami valamilyen típusú változót, illetve értéket jelent.
Lássuk, hogyan oldható ez meg!
5. Válogassuk szét az elemeket típus szerint!
A szétválogatáshoz szakítanunk kell a document.write() függvénnyel való kiiratással. Helyette
érdemes kialakítani három blokkot (div-et), melyek közül a megfelelő blokk .innerHTML
tartalmának bővítésével helyezhetjük el az aktuálisan megjelenítendő elemet, megtörve ezzel
a kényszerű sorrendiséget.
Idáig eljutva kétségtelenül örülhetünk eddigi eredményeinknek, ugyanakkor azt is látnunk kell,
hogy a programunk jelenlegi állapota még nem alkalmas arra, hogy ne csak a window objektum
elemeit tudjuk listázni, hanem annak bármely gyerekének a gyerekeit, sőt azok gyerekeit is.
Ehhez ugyanis minden egyes megjelenített elemnek egyben linknek is kellene lennie,
hogy bármelyikre is kattintva tovább tudjunk menni, egy szinttel lejjebb.
6. Tegyük linkké a listaelemeket!
Ahhoz, hogy a megjelenített elemek gyermekei is előcsalogathatóak legyenek, minden egyes
listaelemet linkké kell alakítani, és ezáltal megoldani, hogy az újonnan betöltődő lista
a kattintott elem gyermekeit mutassa ugyanezen program eredményeként. Másként közelítve:
paraméterezhetővé kell tennünk a programunkat, ahol a paraméter mindig az az objektum,
melynek listázni szeretnénk a gyermekeit. Ha például a window.Math elemeire leszünk
kíváncsiak, akkor a paraméterezés az alábbiak szerint alakuljon:
https://infojegyzet.hu/.../obj/?window.Math
A forráskódban ehhez paraméterváltozót szükséges használnunk az eddig konstans
módon szerepeltett window elem helyett. Továbbá meg kell oldanunk, hogy paraméter hiányában
a window objektum gyermekeit lássuk, pont úgy, mint eddig, csak hivatkozásként
megjelenítve őket. A megvalósítást az alábbi forráskód mutatja:
Programunk aktuális kiegészítése több ponton is magyarázatot érdemelhet.
A location.search
a webcím paraméterének lekérdezésre szolgál, mely a paraméterezés
kezdetét jelentő kérdőjelet is magába foglalja.
A location.search.substr(1)
a paraméter első karaktereként megjelenő kérdőjel levágására szolgál,
vagyis a kifejezés a nulladik karakter utáni első karaktertől kezdődve
adja vissza a szövegrészt.
Az eval(objektum) egy érdekes kifejezés: az objektum, mint szöveges
változó magába foglalja a listázandó kifejezés nevét. Ám mi nem ennek a sztringnek
a szöveges tartalmát szeretnénk elemezni a getOwnPropertyNames() függvénnyel, hanem
a sztring tartalma által meghatározott nevű objektumot. Ennek kifejezésére használjuk az
eval()
függvényt - de hasonlót valójában már a 4. pontban is láthattunk.
Kipróbálva a programot, örülhetünk is, és gyanakodhatunk is. Örülhetünk, mert az újonnan kialakított
linkjeink szépen működnek, kattintás után a paraméter megjelenik az URL-ben, és a legtöbb esetben
az új képernyőtartalom mutatja is a kiválasztott objektumunk saját gyerekeit. Ez volt a cél. Immár
megcsodálhatjuk
az összes matematikai függvényt és konstanst,
ismerős elemeket találhatunk a
az window.location saját elemei között,
vagy éppen áttekinthetjük
az sztringműveletek listáját.
De miért csak egy elem található
a window.document saját gyermekei között?
És miért üres
a window.history, vagy
a window.navigator listája?
7. Keressünk még elemeket!
Valóban az a helyzet, hogy az Object.getOwnPropertyNames nem minden esetben sorolja fel
az összes említhető tulajdonságát (vagyis gyerekét) egy objektumnak. Éppen ezért
hajlamosak lehetünk más megközelítés után nézni, amire van is lehetőségünk, hiszen
például a
for( var elem in window )
{
document.write( "<li> window." + elem )
}
programmal is kiirathatjuk a window objektum elemeit. Persze, jogos az észrevétel: ezúttal sokkal kevesebb
elem került listázásra, mint a korábbi változattal, tehát mondhatnánk, kicsit sem vagyunk előrébb. Ám a
helyzet az, hogy ha ugyanezt a programot nem a window objektumra, hanem a window.document-re próbáljuk
ki, akkor az eddigi 1 helyett százas nagyságrendben kapunk eredményt.
for( var elem in window.document )
{
document.write( "<li> window.document." + elem )
}
Ez pedig arra ösztönözhet, hogy akár
a window.history, vagy
a window.navigator
elemeket is megvizsgáljuk ezzel az új megközelítéssel.
Az eredmény pedig önmagáért beszél: ismét találtunk eddig fel nem lelt elemeket. Úgy kell tehát tökéletesítenünk
a 6. pontig kialakított programunkat, hogy az abban szereplő Object.getOwnPropertyNames által fémjelzett
megközelítést ki kell egészítenünk az imént kipróbált módszerrel. Másként fogalmazva össze kell építenünk a két
lehetőséget. Tegyük meg!
Azt tettük tehát, hogy az új módszerünket jelentő ciklussal végignéztük az objektumunk elemeit, és azok
mindegyikéről meghatároztuk, hogy az szerepelt-e már a tulajdonsagok nevű tömbünkben.
Amelyek még nem szerepeltek benne, azokat a
push()
tömbfüggvény segítségével belehelyeztük. Így programunk most már még teljesebb, még részletesebb.
De vajon nem lehetne-e informatívabb, ha a harmadik blokkban a változók, és konstansok részben
nemcsak az elemek típusát, hanem az értékét is megjelenítenénk?
8. Jelenítsük meg a változók és konstansok értékeit is a típusuk után!
Mint láttuk fentebb már többször is, ha egy elem nevét egy változóban tároljuk, akkor
ennek az elemnek az értékéhez az
eval()
függvénnyel férhetünk hozzá, ahol a függvény paramétere az az változó, aminek az értéke
a kérdéses értékű elem neve.
ertek = eval(nev) ;
Az elképzelés túl szép volna, ha ennyire egyszerű volna. Ám több kritikus pontja is van
a dolognak:
Egyrészt nem minden elemnek van értéke. Például mert még sosem kapott.
Ezen elemek értékének lekérdezése programfutási hibát okozhat. Ezt
valahogyan kezelni kell.
A string tipusú kifejezések értékeivel szintén baj lehet. Baj lehet az,
ha túl hosszú (akár több képernyőnyi) az értékük, és baj lehet az is,
ha HTML kódot tartalmaznak, ami a kiírás során teljesen "szétrúghatja" a
weboldalunkat.
Éppen ezért, ezen problémák kivédésére hozzunk létre egy értékíró függvényt, mely megelőzi a hibás
értékkiolvasást, illetve kiírható állapotba hozza a kritikus tartalmú, vagy hosszúságú szöveges
adatokat is. Ennek az elkészítendő függvénynek az eredményét fogjuk megjeleníteni a programunkban.
A függvénynek paraméterként meg kell kapnia a kiírandó elem típusát,
és az elem nevét tartalmazó változót.
A hibás értékkiolvasást egy
try-catch
szerkezettel lehet megelőzni:
megkíséreljük a kiolvasási műveletet végrehajtani - ha sikerül, minden
rendben, ha pedig nem, akkor a hiba okát fogjuk megjeleníteni.
A string tipusú kifejezésekben kicseréljük a HTML utasításokat jelölő
relációjeleket a hozzájuk tartozó speciális karakterre, hogy azok ne
utasításként értelmeződjenek, hanem kiíródjanak.
A túl hosszú szövegeket rövidítve írjuk ki, de megoldjuk, hogy rájuk húzva
az egeret a teljes szöveg elérhető legyen.
A fentiek alapján elkészült új ertekiro() függvényünk így néz ki:
A függvény felhasználásával pedig csupán egyetlen sort kell kiegészítenünk
a 7. pontban szereplő programváltozatunkban.
(A kiegészítést sortörés nélkül, az eredeti sor folytatásaként kell
a kódban megvalósítani!)
Bár a programunk e változata már mindent tud azon célok közül, amiket az oldal tetején megfogalmaztunk,
ennek ellenére bántó lehet, hogy eljutva
valamelyik "legalsó" szintre
már semmi tájékoztatást nem kapunk arról, hogy hova jutottunk, és ott mi van. Illetve az sem feltétlenül
elegáns, hogy nincs a képernyőnek egy fejléce, mely alapján tájékozódhatnánk, hogy éppen merre járunk,
mit látunk.
Ennyi finomítást talán még megérdemel a művünk.
9. Utolsó simítások
Végül tehát a jobb követhetőség kedvéért adjunk egy fejlécet a programunk listája elé, melyben
kiírjuk a vizsgált elem nevét, típusát, ha lehetséges, akkor az értékét is, és feltüntetjük
a felsorolt gyermek elemek számát! Valamint oldjuk meg, hogy ha esetleg nincs listázott
objektum, függvény, vagy változó, akkor ezt jelöljük egy-egy "nincsenek" szóval! Az oldal
legtetején biztosítsunk lehetőséget az egy szinttel feljebb lépéshez!
A kész program forráskódja az alábbi képre kattintva tekinthető meg.