write(), writeln() – egy kis JavaScript történelem

Egy vizsgateszt kitöltése során találkoztam a JavaScript document.write() utasítással – viszont erről az utasításról még az életben nem hallottam, bár már megszoktam, hogy a vizsgatesztben gyakran olyasmi szerepel, amiről egy szó sem esett az (állami) tanfolyamon, de még a leckék után felsorolt dokumentációkban sem. Úgyhogy utána néztem, s elég érdekes dolgok derültek ki.

Egy ma már alig használt metódus

Napjainkban már a böngészőben megjelenő oldalt leképező DOM fa manipulálása a .js fájlban történik, ill. az utasítás tesztelhető a konzolon. Ha ide írom be a document.write(“Hello, world!”) parancsot, akkor a böngészőből eltűnik az eredeti dokumentum, s csak annyi jelenik meg egy üres oldalon, hogy: Hello, word! – Szemben az .innerHTML metódussal, ami documentumon belül változtatja meg egy element – böngészőben megjelenő – tartalmát, s nem tünteti el az eredeti oldalt.

A két eljárás között ez az alapvető különbség, amire rengeteg oldal hívja fel a figyelmet: “document.write() puts the contents directly to the browser where the user can see it“.

Azaz itt a BOM (Browser Object Model) által hivatkozott windows objektumban egy új document objektum jön létre, s az töltődik be a korábbi html fájl helyére – s az eredeti tartalom eltűnik a böngésző ablakából. Az inspektorban is láthatjuk, hogy egy teljesen új DOM fa vette át az előző helyét.

<html>
  <head></head>
  <body>Hello, world!</body>
</html>

A .write() egy document metódus, így csak a documentre tudjuk rátenni – document.write() -, ami azt jelenti, hogy JavaScript fájlból nem tudjuk semmire se használni – mert egyszerűen nincs, amire használhatnánk. Ennek az az oka, hogy ez a metódus még abból az időből maradt fent, amikor még nem lehetett a .js fájlból manipulálni a html oldalt, pl. még nem létezett az .innerHTML metódus sem, ahogyan azt egy JavaScript utasításokat felsoroló oldal is tanúsítja 2001-ből. Ez azt jelenti, hogy anno ezt az utasítást csak a html fájlban használták <script></script> tagok közé inline módon beszúrva.

Ez a metóduscsalád tulajdonképpen négy metódusból áll. A document.open() utasítás indítja el a document stream-et, a document.write() és a document.writeln() jeleníti meg a zárójelek közé stringben írt tartalmat, amelyek html tag-eket is tartalmazhatnak. Végül a document.close() utasítás zárja le a document stream-et.

Ezen belül, ha egy document stream lezárása után hívjuk meg az write() metódust, akkor az automatikusan hívni fogja az open() metódust, ami törölni fogja az addig felépített HTML oldalt és egy új document stream-et indít el. Így az is világos, hogy ha a HTML oldal betöltődése után hívjuk a write() metódust – pl. konzolról, vagy event handler-ként -, akkor az egy új document stream-et indít el, s ezért törlődik az eredeti oldal.

Tehát nagyon fontos: ezt a metódust csak az oldal betöltődése alatt használhatjuk, ha az oldal betöltése után újra használni akarjuk, akkor az törölni fogja és újraírja a tartalmával a teljes oldalt!

Most pedig jöjjön a Holló Színház!

Továbbá a write() és a wrtiteln() – write line – között az a különbség, hogy a writeln() utasítás a megjelenített tartalmat mindig új sorban kezdi, de csak akkor, ha a script <pre></pre> tagok között fut. Egyébként nem. Ez a körülményes használat ma már persze abszurdnak tűnik, viszont a magyarázatához két dolgot kell tudni, ami még ma is érvényben van.

  • A HTML-be írt tartalom ún. white space-ként kezeli a szóközöket és a sortörést, azaz akárhány szóköz vagy sortörés követi is egymást a kódban, azt a program csak egyetlen szóköznek tekinti, csak egy szóközt jelenít meg. Kivéve ezalól az az eset, amikor a tartalom <pre></pre> tagok között van, ekkor ugyanis az összes bevitt szóköz és sortörés is megjelenik.
  • A blackslash (visszaperjel: \) pedig egy ún. escape karakter. Ez azt jelenti, hogy a visszaperjel után leírt karakter olyan utasításként fog kiértékelődni, amelyet egyébként nem tudnánk bevinni a billentyűzetről. Ezek az utasítások még a telexgépek korából származnak, ugyanis kezdetben a számítógépes karakterkódolás a telexgépekre kifejlesztett ASCII kódolást vette át. Ezek közül két vezérlőkód a legfontosabb: a Carriage Return (‘kocsi vissza’ – a kódja ma: \r), ami a nyomtatófej kocsiját vitte a sor elejére a telexgépen, ill. a Line Feed (‘új sor’ – kódja ma: \n), ami a nyomtatófejet a következő sorra állította. A Windows-ban ez a két utasítás egyszerre használatos (\r\n vagy összevonva: \n), s a kurzort az új sor elejére viszi, s onnan kezdi megjeleníteni a további adatokat).
  • Azaz a ‘visszaperjel + n’ karakterek kettősét a számítógép nem megjelenítendő karakternek értelmezi, hanem egy utasításnak.
  • A writeln() pedig ezt a vezérlőkaraktert használja. A HTML dokumentum viszont nem ismeri fel a vezérlőkaraktereket, kivéve azt az egy esetet, amikor az ilyen karaktert tartalmazó content a <pre></pre> tag-ek között szerepel.
  • Ez akkoriban nem okozott különösebb fennakadást, hiszen a script tag-eket inline szúrták a HTML kódba, így nem sok többlet odafigyelés igényelt, hogy elé és utána még beszúrják a pre tag-et is.
  • A writeln(“tartalom”) helyett használhatjuk a write(“<br>tartalom”) utasítást, hiszen a metódus paraméterébe betehetünk HTML tag-et is. A <br> element pedig egy sortörést hoz létre.

Mire volt jó annak idején ez a ma már használhatatlan metódus?

Nézzünk rá egy példát egy 2001-es kiadású JavaScript tankönyvből (Paul McFedries: Special Edition Using JavaScript):

Azaz akkor használatos ez a metódus, ha

  • tartalmat akarunk a HTML betöltődése alatt elhelyezni az oldalon
  • tartalmat akarunk megjeleníteni egy új ablakban úgy, hogy ahhoz ne kelljen külön HTML fájlt létrehozni
  • frame esetén – ezt az esetet nem részletezem, mert az akkoriban használt <frameset> tag HTML5-ben már nem létezik

Itt pedig egy példa egy másik tankönyvből, hogy hogyan használjuk ezt az eljárást arra, hogy a dokumentumban a betöltés folyamata alatt tartalmat jelenítsünk meg:

A kódon látható, hogy a writeln() utasításokat tartalmazó script element pre tagok közé van zárva.
Majd jön a logikus kérdés: mire jó mindez, ha ugyanezt a tartalmat sima HTML kódban is fel tudjuk írni?

A magyarázat az, hogy a write() metódussal nem csak stringeket, de változókat is meg tudunk jeleníteni. Pl. egy document.write(Date()) utasítással meg tudjuk jeleníteni az oldalon az aznapi dátumot, ami viszont egy statikus oldalkezelés esetén lehetetlen lenne.

A másik felhasználási lehetőség, hogy egy új ablakban egy olyan oldalt jelenítsünk meg, amihez nem tartozik HTML fájl. Például:

var newWindow = window.open();
newWindow.document.open();
newWindow.document.write(“Hello, world!”);
newWindow.document.close();