Úvod

Nejdříve - ač to nejspíš vypadá zvláštně - něco málo ke jménu. Zde popisovaný programovací jazyk byl vytvořen před dávnými a dávnými věky pro prohlížeč Netscape 2 a měl nésti jméno LiveScript. Z marketingových důvodů byl však na poslední chvíli přejmenován na JavaScript, pod kterýmžto jménem je znám dodnes (a nejspíše i na věky), což můžeme směle pokládat za jeho vůbec největší chybu - vysvětlit neznalému rozdíl mezi Javou a JavaScriptem, který je nebetyčný, je pak totiž skoro nemožné. Nutno říci, že ke smůle JavaScriptu, protože narozdíl od Javy je to jazyk pěkný a použitelný (podle všeho vůbec nejpoužívanější programovací jazyk na světě ^_^). Nu, a aby těch zmatků nebylo málo, tak ten samý jazyk byl později standardizován pod jménem ECMAScript. Tak.

Nyní konečně k samotnému jazyku. Svojí syntaxí se inspiroval u jazyků Céčkovské rodiny, takže pro oddělování bloků kódu slouží složené závorky {}, cyklus for vypadá stejně podivně a tak vůbec. Narozdíl od nich se však jedná o jazyk dynamický/skriptovaný, tzn. že kontrola kódu je prováděna až při jeho spuštění (typicky v rámci HTML-stránky v prohlížeči) a vyrobit fatální chyby je tak dosti jednoduché. Na druhou stranu se v něm zase poměrně rychle navrhují nové projekty. Navrch je to jazyk silně objektový, dědičnost je ovšem realizována velmi netypickým (zároveň však velmi mocným) prototypovým způsobem. A aby toho nebylo málo, obsahuje docela dost výpůjček z jazyků funkcionálních. (Proměnné jsou ovšem pořád proměnné a jejich obsah můžete během běhu programu libovolně měnit, takže pozor na to ^_~) Stručně řečeno je toho dost, aby to typického javoidního programátora naprosto znechutilo. Ten nechť vyčká další revize jazyka, která se Javě velmi přiblíží (obsahuje dokonce class), a pak v něm může psát programy, které zase znechutí nás, že.

Přestože kouzlo a krása ECMAScriptu (a zároveň také jeho složitost) leží převážně v těch pokročilejších (rozuměj „ne tak javoidních“) konstruktech, zmíním zde jen ty typické (a také nejčastěji používané). Především všechno v ECMAScriptu je objekt a proměnná (tedy existují implementace, kde jsou k dispozici třeba i konstanty). Proměnné jsou přitom přístupné v celém tom bloku programu, kde byly definovány - globální proměnné z horní úrovně programu všude, lokální proměnné např. uvnitř funkcí nebo smyček pouze tam. Je dobrým zvykem deklaraci proměnné uvádět za pomoci klíčového slova var, aby výše uvedené byla opravdu pravda:

  var cosi
  var cislo = 10
  var str = "Ahoj, jak se máte?"
  var mojeFunkce = function() { … }

Interpretr jazyka se pokusí při zpracování programu proměnným přiřadit nejvhodnější typ. Proměnná cosi tak bude mít typ undefined, protože nic bližšího o ní zatím nevíme. Proměnná cislo bude prostě reálné číslo (přesněji „double-precision 64-bit format IEEE 754 value“), takže pozor na překvapení typu 0.1 + 0.2 = 0.30000000000000004 ^_^ (Příští verze jazyka by měla obsahovat celočíselnou aritmetiku.) Proměnná str je řetězec, a to dokonce Unicodový, takže můžete vesele zapomenout na trable s češtinou z jiných jazyků. Proměnná mojeFunkce je pak definice funkce (bez parametrů). Dá se to zapsat i tradičnějším způsobem, ale takhle krásně vynikne, že funkce v ECMAScriptu jsou zároveň i proměnné a tudíž s nimi jako s proměnnými také můžete zacházet (přiřazovat je jiným proměnným, předávat jako parametry…).

Kromě toho, že (skoro) všechno jsou proměnné, je také (skoro) všechno zároveň i objekt. Několik objektů máme předdefinovaných (Date, Math, RegExp, String…), další dodá hostující prostředí (viz kapitola o DOMu) a ještě další si samozřejmě můžeme vytvořit sami. Tak kupříkladu výše uvedená proměnná str je zároveň objektem typu String, tudíž přímo na ní máme k dispozici všechny vlastnosti a metody definované pro tento objekt, např.

  > var str = "Ahoj, jak se máte?"
  > str.length
  18
  > str[0]
  A
  > str.replace('Ahoj', 'Dobrý den')
  Dobrý den, jak se máte?
  > str
  Ahoj, jak se máte?
  > str = str.replace('Ahoj', 'Dobrý den')
  Dobrý den, jak se máte?
  > "můj řetězec".length
  11
  > 'jiný "můj" řetězec'.substring(3,11)
  ý "můj" ř

Jak je vidět, vlastnosti a metody objektu String se aplikují tečkovou notací, a to buď na příslušnou proměnnou str (která je typu String) nebo dokonce přímo na samotný řetězec. Obsah tohoto řetězce se přitom nemění, případná nová hodnota je pouze předána jako návratová (takže až přiřazení této hodnoty do původní proměnné ji změní). Zajímavostí je, že k prvkům řetězce se dá přistupovat stejně jako k prvkům pole, tj. pomocí notace [], jen indexace polí v ECMAScriptu probíhá od 0 do (POLE.length-1). Povšimněte si, že řetězcová proměnná se dá zavést pomocí normálních uvozovek "" nebo pomocí apostrofů '', přičemž obé se dá vzájemně kombinovat (pozor ovšem na správné párování).

Dále máme v ECMAScriptu k dispozici standardní sadu operátorů:

  > var num = 3
  > num = num + 1
  4
  > num += 1
  5
  > num++
  5
  > num
  6
  > --num
  5

Sekvence num++ přitom nejdříve vrátí hodnotu proměnné num a teprve potom ji zvýší o jedničku, zatímco sekvence --num ji naopak nejdříve o jedničku sníží a teprve potom vrátí. Operátor + se přitom příliš nedívá po typu proměnných, na které je aplikován, a dá se použít jak pro klasické sčítání, tak i spojování řetězců:

  > 5 + 3
  8
  > 'Jméno' + ' ' + 'Příjmení'
  Jméno Příjmení

Operátory porovnání jsou klasické a fungují také mezi různými typy:

  > 3 == 3
  true
  > 4 < 3
  false
  > "ahoj" == 'ahoj'
  true
  > 'abcd' < 'bcde'
  true

Ke kontrole běhu programu máme k dispozici klasické i méně klasické rozhodování

  var a = 1

  var b
  if (a == 1) {
    b = 'Jednička!'
  } else {
    b = 'Nejednička!'
  }

  var c = (a == 1) ? 'Jednička!' : 'Nejednička!'

  var d
  switch (a) {
    case 1:
      b = 'Jednička!'
      break
    default:
      b = 'Nejednička!'
  }

plus tři klasické cykly

  for (var i=0; i<5; i++) {
    …
  }
  
  var j = 0
  while (i<5) {
    …
    i++
  }
  
  var k = 0
  repeat {
    …
    k++
  } while (k<5)

To nejzajímavější v ECMAScriptu je spojeno s objekty a zvláště funkcemi, překračuje to však značně toto úvodní povídání, proto si to ponecháme na jindy.

Objekty v ECMAScriptu

Samotný ECMAScript sám o sobě má k dispozici následující objekty: Array, Boolean, Date, Error, EvalError, Function, Math, Number, Object, RangeError, ReferenceError, RegExp, String, SyntaxError, TypeError, URIError. Pozorný čtenář si zřejmě všiml, že tam není žádný objekt pro práci s něčím tak základním, jako jsou soubory. Možná něco tak důležitého je k dispozici přímo v základu jazyka, bez vlastního objektu? Nikoli, není tomu tak. ECMAScript - a nebudete první, jestli se tomu budete divit - skutečně vůbec nemá žádné metody, vlastnosti ani objekty pro interakci s okolím. Pouze samotný programovací jazyk se všemi vlastními konstrukcemi a konstrukty potřebnými pro vlastní programování - a vše ostatní je ponecháno na hostujícím prostředí. A tak implementace ECMAScriptu pro příkazovou řádku od Mozilly umí třeba print, varianta JScript od Microsoftu (kterou můžete použít z příkazové řádky pod Windows) umí samozřejmě (mimo jiné) pracovat se soubory v souborovém systému a varianta ECMAScriptu ve Photoshopu od Adobe umí „naprosto nečekaně“ nejrůznější kouzla s obrázky. Prostředí, se kterým se dostanete asi nejvíce do kontaktu - totiž webový prohlížeč, pak poskytuje univerzální výstupní funkci alert(), která na uživatele „vyplivne“ dobře známé (a často proklínané) kontextové okénko.

Jak už jsem se zmínil v předchozím odstavci, k jednotlivým vlastnostem a metodám objektu se přistupuje pomocí tečkové notace. Ukažme si pár dalších příkladů. Užitečným objektem je třebas Date. Jeho největším „podrazem“ (kromě zcela zcestně navržené, ale dnes už bohudík nedoporučované metody getYear()) je, že měsíce počítá od 0:

  > var datum = new Date()
  > datum
  Thu Dec 13 2007 02:06:33 GMT+0100 (CET)
  > var str = datum.getDate() + '.' + (datum.getMonth()+1) + '.' + datum.getFullYear()
  > str
  13.12.2007

Výše uvedený kód uloží do proměnné datum údaj o čase aktuálním v okamžiku provedení příkazu. Toho se občas využívá třebas pro implementaci „stopek“ - do jedné proměnné uložíte stav na začátku, do druhé na konci a následně odečtete rozdíl.

Dalším užitečným objektem je Math. Kromě několika základních matematických konstant, např.

  > Math.PI
  3.141592653589793
  > Math.E
  2.718281828459045

nabízí i základní matematické funkce, např.

  > var n = Math.cos( Math.PI )
  > n
  -1
  > Math.abs( n )
  1

S ostatními objekty se pak setkáte spíše nepřímo. Jako např. s objektem String v předchozí kapitole - zavedení řetězcové proměnné (nebo pouhé přímé použití řetězce) vytvoří automaticky objekt, který je typu String a má tudíž všechny jeho vlastnosti. Podobně regulární výrazy (objekt RegExp) jsou přístupné přímým zavedením (příklad podle developer.mozilla.org):

  > var re = /(\w+)\s(\w+)/g
  > var str = "Jan Novák"
  > str.replace(re, "$2, $1")
  Nov, Janák

Jak jsem se výše rozplýval, že v ECMAScriptu je řetězec v Unicode-kódování, tak regulární výrazy nám zamrzly v počítačové prehistorii - \w odchytí všechny alfanumerické znaky (včetně podtržítka, tj. [A-Za-z0-9_]), ale pouze z „Basic Latin“… Nezbývá, než si češtinu a slovenštinu „připsat“:

  > var wU = "[A-Za-z0-9_ÁÄČĎÉĚÍĹĽŇÓÔŘŔŠŤÚŮÝŽáäčďéěíĺľňóôřŕšťúůýž]"
  > var re = new RegExp( '('+wU+'+)\\s('+wU+'+)', 'g' )
  > var str = "Jan Novák"
  > str.replace(re, "$2, $1")
  Novák, Jan

Přímá definice regulárního výrazu jako v předchozím příkladu by byla nepřehledná, proto jsem nejdříve nadefinoval rozšířený speciální charakter wU, který si poradí i s českými a slovenskými alfanumerickými znaky, a ten jsem následně použil při vytvoření požadovaného regulárního výrazu, tentokrát pomocí konstruktoru objektu.

Objekty v ECMAScriptu jsou vlastně hash-pole přístupná přes tečkovou notaci. Ukažme si to na nějakém vlastním objektu:

  > var clovek = {
      jmeno : {
        krestni : 'Jan',
        prijmeni : 'Novák'
      },
      narozeni : {
        den : 13,
        mesic : 1,
        rok : 1980
      },
      zamestnani : 'učitel'
    }
  > clovek.zamestnani
  učitel
  > clovek.jmeno.prijmeni
  Novák

Již existující objekt můžeme rozšířit o další vlastnosti či metody:

  > clovek.getCeleJmeno = function() {
      return this.jmeno.krestni + ' ' + this.jmeno.prijmeni
    }
    clovek.getDatumNarozeni = function() {
      return this.narozeni.den + '.' + this.narozeni.mesic+'.'+this.narozeni.rok
    }
  > clovek.getCeleJmeno()
  Jan Novák
  > clovek.getDatumNarozeni()
  13.1.1980

„Magické“ slůvko this se odvolává na aktuální kontext, což v tomto případě znamená příslušný nadřazený objekt clovek. Mimochodem existuje varianta cyklu for, která umí iterovat po vlastnostech (a metodách objektu). Následující kód

  var strVlastnosti = ''
  for (var i in clovek) {
    strVlastnosti += i + '\n'
  }

vrátí v řetězcové proměnné strVlastnosti seznam

  jmeno
  narozeni
  zamestnani
  getCeleJmeno
  getDatumNarozeni

zatímco následující kód

  var strVlastnostiDefinice = ''
  for (var i in clovek) {
    strVlastnostiDefinice += i + ' : ' + clovek[i] + '\n'
  }

k němu přidá i příslušnou identifikaci dané vlastnosti/metody:

  jmeno : [object Object]
  narozeni : [object Object]
  zamestnani : učitel
  getCeleJmeno : function() {
  return this.jmeno.krestni + " " + this.jmeno.prijmeni;
  }
  getDatumNarozeni : function() {
  return this.narozeni.den + "." + this.narozeni.mesic+"."+this.narozeni.rok;
  }

Kód využívá drobného triku - k vlastnostem objektu je totiž možné přistoupit nejen pomocí tečkové notace, ale také jako k hash-poli indexovanému řetězcem. A protože proměnná i ve výše uvedených cyklech je řetězcová (probíhá názvy vlastností a metod objektu), způsobí kód clovek[i] vypsání definice příslušné vlastnosti (postupně se totiž bude volat clovek['jmeno']clovek['getDatumNarozeni']). Kdybychom do cyklu napsali clovek.i, vrátí se nám pětkrát undefined, protože tento kód se bude snažit (pro každou z pěti vlastností objektu clovek) vypsat definici vlastnosti i objektu clovek a takovou jsme přece vůbec nedefinovali.

Výše uvedený kód funguje i u objektů předdefinovaných, ale je třeba poznamenat, že ne všechny vlastnosti všech objektů je možno tímto způsobem vypsat.

Ve světle výše uvedených poznatků je celkem jednoduché pochopení chování objektu Array, se kterým se setkáte velmi často v podobě různých návratových hodnot mnoha metod DOMu. Pole v ECMAScriptu totiž nejsou vlastně nic jiného než objekty, hash-mapy, které mají navíc délku a spoustu užitečných metod (jako např. reverse(), sort(), slice() apod.). Největšími dvěma „podrazy“, které vás u polí mohou potkat, je číselná indexace prvnků pole, která - jak je u ECMAScriptu ošklivým zvykem - začíná nulou, a to, že délka pole je číslo o jedničku větší než největší index v poli, ať už jsou indexy menší použity nebo ne:

  > var pole = []
  > pole[0] = 'první prvek'
  > pole[99] = 'poslední prvek'
  > pole.length
  100

Nejužitečnější vlastností polí v ECMAScriptu je pak právě to, že jsou to vlastně objekty. Narozdíl od mnoha jiných programovacích jazyků tak můžete k indexaci prvků pole použít doslova co vás napadne:

  > var pocetZakuVeTridach = []
    pocetZakuVeTridach['2A'] = 27
    pocetZakuVeTridach['2B'] = 23
    pocetZakuVeTridach['3A'] = 31
    pocetZakuVeTridach['3B'] = 25
  > pocetZakuVeTridach['3B']
  25
  > var trida = '3A'
  > pocetZakuVeTridach[ trida ]
  31

Takto definovaná pole mají nulovou délku, takže po jejich prvcích nemůžete iterovat pomocí kódu např. for (var i=0, len=pocetZakuVeTridach.length; i<len; i++) { … }. Ale jako vždy máte k dispozici cyklus for (var i in pocetZakuVeTridach) { … }, který „projede“ všechny vlastnosti příslušného objektu, tj. postupně 2A, 2B, 3A a 3B.

DOM (Document Object Model)

Asi vůbec nejrozšířenějším hostujícím prostředím pro ECMAScript jsou webové prohlížeče. V jejich kontextu k běžnému (výše probranému) „arzenálu“ jazyka patří především objekt window (bohužel dosud nikde nestandardizovaný), který zapouzdřuje takové užitečné vlastnosti jako třeba

plus všechny proměnné (tj. i funkce!), které v rámci příslušné (HTML-)stránky nadefinujete. Dále je k dispozici třeba již výše zmíněná metoda alert() sloužící k výpisu informací pomocí popup-okénka nebo funkce pro ovládání posunu stránky či velikosti okna prohlížeče. Objekt window je přitom rodičem všech těchto podobjektů, vlastností a metod, z kteréhožto důvodu jsou následující volání ekvivalentní:

  window.alert( 'Ahoj!' )
  alert( 'Ahoj!' )

tj. objekt window je možno ze zápisů vynechat (jak se také celkem pochopitelně zhusta činí).

Zdaleka nejvýznamějším příspěvkem prohlížečů do struktury ECMAScriptu jsou však objekty, vlastnosti a metody DOMu. Z hlediska DOMu představuje zpracovávaný dokument stromečkovou strukturu vzájemně provázaných objektů, tj. následující jednoduchý HTML-dokument

  <html>
    <head>
      <title> Název stránky </title>
    </head>
    <body>
      <h1> Nadpis </h1>
      <p> odstavec s textem </p>
    </body>
  </html>

by měl v DOMu asi takovouto reprezentaci (podle developer.mozilla.org):

  window
    |- document
         |- HTML
	    |- HEAD
	    |  |- TITLE
	    |     |- Název stránky
	    |- BODY
	       |- H1
	       |  |- Nadpis
	       |- P
	          |- odstavec s textem

kde černě jsou vyznačeny objekty ECMAScriptu příslušející prohlížeči (window) a vrchní DOM-objekt zpracovávaného dokumentu (document), modře objekty odpovídající elementům a zeleně objekty odpovídající textu. Potud teorie. Praxe je však o dost složitější. Předně pouze v HTML-dokumentu vyhovujícímu jistým pravidlům může element BODY obsahovat pouze blokové elementy a jen za takového předpokladu by výše uvedená reprezentace byla pravdivá. V praxi za a) může být v BODY cokoliv a za b) prohlížeč může na takové „detaily“ vyloženě „kašlat“ a udělat si reprezentaci podle sebe. Druhá nejčastější DOM-reprezentace výše uvedeného HTML-dokumentu by nejspíš vypadala takto:

  window
    |- document
         |- HTML
	    |- HEAD
	    |  |- TITLE
	    |     |- Název stránky
	    |- BODY
	       |-  \n 
	       |- H1
	       |  |- Nadpis
	       |-  \n 
	       |- P
	       |  |- odstavec s textem
	       |-  \n 

Zde si prohlížeč do DOMu doplnil textové node'y (představované mezerami a novými řádky), které uvnitř BODY mezi elementy H1 a P skutečně jsou, i když evidentně nemají žádný význam pro výsledné zobrazení dokumentu v prohlížeči. Tím to ovšem pro HTML-dokumenty ani zdaleka nekončí. Jak všichni vědí, z historických důvodů musí umět prohlížeče zobrazit cokoliv, co jim předhodíte. A to v naprosté většině případů opravdu není well-formed HTML… Takže i naprosto nesmyslný dokument si musí umět prohlížeč doplnit na nějakou objektovou reprezentaci. No a způsob, jak ho doplnit, není nikde popsaný, takže to každý program udělá nejspíš trochu jinak. (Připravovaná specifikace HTML5 se poprvé v historii právě na tomto poli snaží udělat trochu „pořádek“ a nějaká trochu rozumnější pravidla pro tvorbu DOM-reprezentace zavést.)

Za této situace je asi celkem pochopitelné, že přepečlivě vymyšlený standard DOMu funguje tak možná v rámci uzavřených prostředí na přesně definovaných XML-dokumentech, ale v reálném webu na HTML se tak trochu míjí s cílem. Nebo abych se vyjádřil přesněji - většina generických metod a vlastností DOMu, které slouží k manipulaci s objektovou DOM-reprezentací dokumentu tak, aby zůstala zachována jeho konzistence, je pro případ HTML buď nepoužitelná nebo zbytečně složitá, případně úplně zbytečná.

DOMy existují vlastně dva - jeden základní, společný všem dokumentům s XML-strukturou, a druhý speciální, čistě pro HTML-dokumenty. Ten druhý obsahuje všechno z toho prvního, ale jak už jsem říkal, je to v rámci HTML skoro k ničemu. Naštěstí obsahuje spoustu doplňků cílených přímo na HTML, které použitelné naopak jsou a velmi dobře. Tak pokud kupříkladu proměnná el obsahuje referenci na DOM-objekt představující element P ve výše uvedeném HTML-dokumentu, máme (mimo jiných) k dispozici tyto samovysvětlující generické metody DOMu

  el.setAttribute( 'style', 'color: red;' )
  el.getAttribute( 'style' )

ale zároveň i vlastnosti specifické, které vyplývají z toho, že je to HTML-element a v rámci HTML jsou na něm k dispozici některé předem definované vlastnosti, jako např.

  el.className
  el.title
  el.id

Zjednodušeně se dá říci, že HTML DOM rozšiřuje standardní DOM, který obsahuje obecné metody na přístup k vlastnostem objektů a jejich změny, o speciální HTML-zaměřené „zkratky“ k dosažení téhož. Přitom prohlížeče nabízejí těchto „zkratek“ ještě více (a netřeba zmiňovat, že jsou často jednodušší na použití, rychlejší na provedení a velmi často řeší věci, na které se v rámci standardního DOMu nedostalo). Úkolem webového programátora je se v tomhle všem zmatku vyznat. Hlavně vědět, kterou metodu či vlastnost kdy a kde může použít ^_^ V další kapitole se pokusím to nejužitečnější z DOMu (ať už standardizovaného nebo specifického pro prohlížeče) ukázat na jednoduchých příkladech.

Ukázky kódu

Ukázky kódu v této kapitole budou operovat nad následujícím HTML-dokumentem:

  <html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title> testovací dokument </title>
    <script type="text/javascript" src="testovaci.js"></script>
  </head>
  <body onload="init()">
    <h2> Nadpis testovacího HTML-dokumentu </h2>
    <div id="par1" class="lichy">
      První odstavec. Tady bude jenom text. 
      <div>Zato ale ve více odstavcích.</div> 
      <div>To abychom mohli předvést kontextualitu DOMovských metod.</div>
    </div> 
    <div id="par2" class="sudy">
      Druhý odstavec. Sem toho napíšeme víc:
      <input type="text" value="počáteční text" onkeyup="zpracujInput(this)">
      A ještě <b>něco</b> a <b>něco</b>.
    </div> 
    <div id="par3" class="lichy trida">
      Ve třetím odstavci vyrobíme menu:
      <select id="vyber" onchange="zpracujSelect()">
        <option value="v1">1. hodnota</select> 
        <option value="v2">2. hodnota</select> 
        <option value="v3">3. hodnota</select> 
      </select>
      <br>
      A přidáme nějaké <button onclick="zpracujButton()">tlačítko</button>, 
      abychom mohli volat funkce ECMAScriptu i jinak.
    </div> 
  </body>
  </html>

Přitom v doprovodném ECMAScriptím souboru jsou nadefinované použité funkce, takže oba soubory dohromady můžete využít pro testování ukázek.

Z předchozí kapitoly byste měli tušit, jak přibližně bude vypadat objektová DOM-reprezentace tohoto HTML-dokumentu. V následujících ukázkách se po ní naučíme „navigovat“ a zjišťovat či měnit některé její vlastnosti. Nejdříve ale něco o tom, jak se k ECMAScriptu z vnitřku dokumentu vůbec dostat.

Obecně můžeme vyvolat zpracování ECMAScriptího programu dvěma způsoby - buď zpracováním kódu přímo při načítání dokumentu nebo jako odpověď na nějaké události ve stránce (kliknutí na odkaz či tlačítko, výběr položky z menu, vepsání textu do vstupního pole, posun myši nad nějakým objektem apod.). Typ události, která se bude zachytávat a následně zpracovávat, můžeme svázat s objektem, u kterého tuto událost budeme odchytávat, dvěma různými způsoby. Jeden je čistě DOMovský a spočívá v použití metody addEventListener(). Druhý, použitý v ukázce, kombinuje HTML s ECMAScriptem a kromě toho, že je průhlednější a přímočařejší, dá se téměř bez obav použít snad ve všech prohlížečích.

Co se prvního způsobu vykonávání ECMAScript-programu týká, tak prohlížeč zpracovává kód tak, jak načítá stránku, což znamená, že ihned po objevení dat programu je začne zpracovávat. Jelikož se programy uvádějí ve stránce typicky v hlavičce dokumentu, opravdu není dobrý nápad uvést na tomto místě příkazy pro zpracování objektů ve stránce, když ta se ještě nestihla načíst ^_^ Je dobrým zvykem, že veškerý kód, který ke svému běhu potřebuje DOMovskou strukturu celé stránky, se uvádí jako parametr události load na elementu BODY - tak je totiž (celkem) zajištěno, že všechny objekty, ke kterým by mohl přistupovat, už budou existovat.

V ukázce jsou definovány čtyři „zachytávače“ událostí - onload, onkeyup, onchange a onclick. S elementární znalostí angličtiny jsou v podstatě samovysvětlující:

Událostí, které můžete odchytávat, existuje veliké množství - z těch rozšířenějších např. load, unload, abort, error, select, change, submit, reset, keydown, keyup, keypress, click, mousedown, mouseup, mouseover, mousemove, mouseout, focus, blur, resize, scroll. Některé z nich má smysl odchytávat všude (třeba události související s pohybem myši), jiné jenom ve vhodných kontextech (např. load typicky u celé stránky, případně třeba obrázků).

A) Podívejme se nejdříve na kód, který je uveden na začátku souboru testovaci.js (tj. část A):

  var globalTXT = 'Ahoj!'
  var globalFN = function(paramTXT) {
    alert( paramTXT )
  }
  globalFN( globalTXT )

Protože ECMAScript je interpretovaný jazyk, je zdrojový kód zpracováván řádku po řáce tak, jak je načítán. Z tohoto důvodu musíme funkci globalFN() nejdříve nadefinovat, a teprve potom zavolat. Kdybychom se ji pokusili zavolat dříve, dojde k běhové chybě, protože žádáme vyvolání funkce, která (ještě) neexistuje. Z téhož důvodu nemůžeme takovýmto způsobem manipulovat s DOM-obrazem dokumentu - v této chvíli totiž ještě není připraven, protože stránka nebyla dosud celá načtena a zpracována! Povšimněte si ještě, že zavolání funkce alert() „zamrzne“ prohlížeč. Teprve po zavření popup-okénka pokračuje prohlížeč ve zpracovávání zbytku zdrojových dat. A protože tento kód je umístěn na začátku ECMAScriptího souboru, který sám je v rámci HTML-stránky načítán už v její hlavičce, znamená to, že dokud uživatel toto popup-okénko nezavře, nebude stránka zobrazena.

Zbytek ECMAScript-kódu (tj. části B, C, D, E a F) už jsou pouze definice funkcí, objektů a proměnných, tj. žádné výkonnové části, které by něco dělaly, proto se na načítání HTML-stránky už nijak vizuálně neprojevují. S výjimkou části F, která obsahuje pomocné funkce, se jedná o funkce zapouzdřující kusy kódu, které budou vyvolány (a tudíž provedeny) jako reakce na čtyři výše uvedené události. Podívejme se na ně jednu po druhé.

B) Část B obsahuje definici objektu docInfo a kód vyvolaný po načtení stránky (událost load na HTML-elementu BODY), tj. funkci init():

var docInfo = {
  ID : 'Objekt s informacemi o HTML-stránce.'
}
var init = function() {
  // reference na kořenový element HTML-stránky
  docInfo.root = document.documentElement
  // kolekce všech DIVů v HTML-stránce
  var divs = document.getElementsByTagName('DIV')
  docInfo.divs = divs
  // kolekce všech DIVů uvnitř DIVu s ID 'par1'
  var prvniDIV = document.getElementById('par1')
  docInfo.divsInner = prvniDIV.getElementsByTagName('DIV')
  // výběr těch DIVů ze všech DIVů, které mají (neprázdný) atribut @class
  var divsWithClass = []
  for (var i=0, l=divs.length; i<l; i++) {
    if ( divs[i].className != '' ) {
      divsWithClass[ divsWithClass.length ] = divs[i]
    }
  }
  docInfo.divsWithClass = divsWithClass
  // HTML-obsah prvniho DIVu
  docInfo.prvniDIVhtml = prvniDIV.innerHTML
  // reference na první element INPUT ve stránce (a zde také jediný)
  docInfo.input = document.getElementsByTagName('INPUT')[0]
  // reference na element SELECT s ID 'vyber'
  docInfo.select = document.getElementById('vyber')
}

Již při načítání stránky bude vytvořen objekt docInfo, který bude obsahovat právě jednu textovou vlastnost ID. Po zavolání funkce init() budou do tohoto objektu doplněny další vlastnosti: root, divs, divsInner, divsWithClass, prvniDIVhtml, input, select.

  

  

  

Poznámky