Eingewebt

Von Webdesignern und -benutzern zugleich geliebt und gehasst, ist Javascript auf dem Wege, nach Irrungen und Wirrungen erwachsen zu werden.

In Pocket speichern vorlesen Druckansicht 31 Kommentare lesen
Lesezeit: 14 Min.
Von
  • Christine Kühnel
Inhaltsverzeichnis

Wer Javascript sagt, denkt meist an Scripts in HTML-Dateien, die Browser auf Clients ausführen. Das beginnt bei simplen Einzeilern und reicht bis zu komplexen DHTML-Anwendungen sowie der Dynamisierung der Inhalte von HTML-Dokumenten im Browser. Ganz korrekt ist dieser Sprachgebrauch nicht. Die Sprache selbst - inzwischen weit gehend am Standard Ecmascript [1] orientiert - bildet nur einen Teil, den Kern (core), und bietet vor allem die notwendigen Werkzeuge. Das Material liefert die Umgebung in Form der Dokumente mit all ihren Elementen auf der einen Seite und in Form des Browsers, der Container anbietet, in denen die Scripts laufen und Dokumente sichtbar werden.

Gängigem Sprachgebrauch folgend, der all das unter dem Begriff Javascript zusammenfasst, beschäftigt sich dieses Tutorial mit all diesen Komponenten. Dass Javascript nicht auf Browser und HTML-Dokumente beschränkt, sondern in anderen Umgebungen einsetzbar ist, soll hier nicht Thema sein.

In den letzten Jahren ist das Spektrum des Webmachbaren deutlich breiter geworden. Was noch vor knapp drei Jahren ein Beitrag der iX [6] „Silberstreif am Horizont“ nannte - das Vorliegen eines einheitlichen Objektmodells der Webdokumente (DOM) vom W3C [2], das versprach, endlich Ordnung in das Chaos der Objektmodelle zu bringen -, ist dank der inzwischen vorhandenen Unterstützung durch die gängigen Browser helles Morgenlicht. Webautoren können Scripts anbieten, ohne für jeden Browser ein eigenes Süppchen kochen zu müssen. In vielen Fällen reicht heute schon eine Unterscheidung in diejenigen Browser, die damit umgehen können, und all die anderen, die dem Benutzer die Inhalte ohne Scriptunterstützung vermitteln sollen.

Dies Javascript-Tutorial folgt der eingangs geschilderten Struktur und beschäftigt sich zunächst mit dem Kern, der Sprache (Ecmascript) und den Mitteln, die sie bietet. Der zweite Teil geht auf das DOM ein und den Umgang damit. Ein dritter Teil soll all das diskutieren, was außerhalb von Sprache und DOM liegt, und sich Fragen widmen, die der Einsatz von Javascript in einer zwar geglätteten, aber keinesfalls ebenen Browserlandschaft aufwirft.

Javascript ist eine Programmiersprache wie viele andere. Sie kennt Ausdrücke, Anweisungen, Datentypen, Operatoren, Funktionen und Objekte - damit viel Bekanntes, für das es nur der konkreten Syntax bedarf, die man der Dokumentation entnehmen kann. Die Sprache hat aber ein paar Besonderheiten: Sie verwendet beispielsweise die automatische Typkonvertierung und verlangt weder die Festlegung eines Datentyps noch, dass Variablen expliziert deklariert werden. Der Datentyp ergibt sich durch die Zuweisung eines Werts.

Javascript-Datentypen
number Zahlen: Javascript kennt keine explizite Unterscheidung wie andere Sprachen (integer, float et cetera).
Boolean Wahrheitswerte: true/false
String Zeichenkette
Null Enthält genau einen Wert: null.
Undefined Enthält genau einen Wert: undefined.
object ungeordnete Menge von Eigenschaften
var Nummer  = 14;                         /* number */
var Strasse = 'Schillerstr. '; /* string */

In Fortsetzung kann man später schreiben:

Nummer = Strasse + Nummer;        /* string     */
Nachbarhaus = Nummer + 2; /* number */

Für Nummer erhält man dank der automatischen Typkonvertierung nun den Zeichenkettenwert „Schillerstr. 14“, während „das Nachbarhaus“ vom Typ number ist. Das mag bequem sein, erfordert jedoch Disziplin im Umgang damit.

Besser ist es, Variablen unter Zuhilfenahme des Schlüsselwortes var eingangs zu deklarieren, eventuell zu initialisieren und die Verständlichkeit sowie Lesbarkeit des Codes nicht durch Anweisungen wie oben zunichte zu machen, indem Nummer zur Zeichenkette wird. Geschickter ist in diesem Fall:

var Strasse = '' , Nummer;
var Nummer = 14; /* number */
var Strasse = 'Schillerstr. '; /* string */
Strasse = Strasse + Nummer; /* string */

Außerdem unterscheidet Javascript zwischen Groß- und Kleinschreibung:

Strasse = strasse + ' ' + Nummer;

quittiert Mozilla mit „Error: strasse is not defined“.

Dieses Tutorial geht nicht auf alle Operatoren und deren Präzedenz ein. Die Funktion der verwendeten ergibt sich aus dem Kontext. Die Präzedenz folgt den üblichen Regeln. Vollständige Listen finden sich in der Dokumentation (siehe „Online-Ressourcen“). Erwähnt seien hier nur einige wichtige Javascript- oder besser Ecmascript-spezifische.

Online-Ressourcen
ECMA-262 - Ecmascript Language
Specification www.ecma-international.org/publications/files/ecma-st/Ecma-262.pdf
[W3C:] Document Object Model (DOM) www.w3.org/DOM/
[Netscape:] Core Javascript Guide 1.5 devedge.netscape.com/library/manuals/2000/javascript/1.5/guide/
[Microsoft:] MSDN Library-HTML and Dynamic HTML msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/dhtml_node_entry.asp
FAQ
de.comp.lang.javascript dcljs.de/faq/
The Web Standards Project www.webstandards.org/
javascript.faqts www.faqts.com/knowledge_base/index.phtml/fid/53/

typeof liefert den Typ eines Ausdrucks.
Mehr Infos

Listing 1: <typeof>

var Wert, Typ;
var Alter = 50;
Wert = Alter;
Typ = typeof Alter;
Alter += ' Jahre'
alert( '"Alter" hatte den Wert "' + Wert
+ '" und war vom Typ "' + Typ + '".\n'
+ '"Alter" hat nun den Wert "' + Alter
+ '" und ist vom Typ "' + typeof Alter + '".\n');
  • typeof liefert den Typ eines Ausdrucks, wie Listing 1 und Abbildung 1 veranschaulichen
  • void wertet einen Ausdruck aus und liefert anschließend undefined. Bei Aktivierung des folgenden Links wird lediglich ein in der Seite enthaltenes Formular namens „Form“ abgeschickt:
<a href="javascript:void(document.Form.submit())">
Schick das Formular ab</a>

Der Operator new ist unabdingbar, wenn es um Objekte geht. Dazu weiter unten mehr.

Funktionen zu schreiben und zu verwenden ist zunächst wenig spektakulär. Sie können an jeder beliebigen Stelle deklariert werden; es ist lediglich sicherzustellen, dass sie beim Aufruf schon geladen sind (siehe Listing 2).

Mehr Infos

Listing 2: Einfache Funktion

function tuwas(x)
{
alert('Hallo, ich bin Funktion "tuwas()", mir wurde "'
+ x + '" mit auf den Weg gegeben.');
}
tuwas(17);
tuwas('ein Text');

Interessanter ist der Geltungsbereich von Variablen in Funktionen. Mit Hilfe von var deklarierte Variablen befinden sich in dem Scope, in dem die Deklaration steht. Ist das innerhalb einer Funktion, wird die Variable damit zur einer ihrer lokalen. Variablen ohne explizite Deklaration (var) gelten immer im globalen Scope. Genau genommen werden sie zur Eigenschaft des globalen Objektes im Sinne von Ecmascript.

Javascript enthält eine Reihe implementierter Funktionen. Netscape nennt sie „top-level predefined functions“. Sie sind in der Betrachtungsweise von Ecmascript ebenfalls Funktionen des globalen Objekts. Einige in der Praxis häufig anzutreffende seien hier erwähnt.

  • eval() wertet einen String als Javascript-Code aus und führt, so es sich um Anweisungen handelt, diese aus.

Diese Funktion sieht man viel zu oft im Web, meist, wenn eine Anweisung erst zur Laufzeit bekannte Objekte benutzen soll. Genau in diesen Fällen gibt es jedoch in aller Regel Einfacheres als das ressourcenhungrige eval().

eval("document.Formular.Feld" + args[i] + ".value = 0");

lässt sich einfacher realisieren:

document.Formular['Feld' + args[i]].value = 0;

parseInt() und parseFloat() werten eine Zeichenkette aus, deren Beginn als Zahl interpretierbar ist, und geben diesen als Typ number zurück.

Im Unterschied zur automatischen Typkonvertierung klappt das auch, wenn nur der Anfang der Zeichenkette als numerischer Wert interpretierbar ist. Außerdem lässt parseInt() nicht nur Zahlen aus dem Dezimalsystem, sondern mit beliebiger Basis zu. In der Praxis interessant sind gelegentlich Hexadezimal- und Oktalzahlen. Bequem und tückisch in diesem Zusammenhang: Die Funktion ermittelt ohne explizite Angabe der Basis diese automatisch. Beginnt die Zeichenfolge mit „0x“, wird Basis 16 angenommen, beginnt sie mit „0“, aber nicht mit „0x“, Basis 8, sonst Basis 10. Vornullen von dezimalen Zahlen geraten da schon mal zum Stolperstein. Gibt man der Funktion einen weiteren Parameter auf den Weg, der die Basis explizit vorgibt, entfällt der Stolperstein.

parseInt([3,14])            /*       3   */ 
parseInt('4711') /* 4711 */
parseInt('04711') /* 2505 */
parseInt('0x4711') /* 18193 */
parseInt('04711',10) /* 4711 */
parseFloat('047.11') /* 47.11 */
parseFloat('47,11') /* 47 */
parseInt('keine Zahl') /* NaN */

isNaN() erkennt, ob ein Ausdruck nicht vom Typ number ist (NaN = Not a Number). Für Formularprüfungen bietet sich diese Funktion in Kombination mit parseInt() und parseFloat() geradezu an. In Listing 3 wird das Formular nur abgeschickt, wenn das Eingabefeld einen numerischen Wert enthält.

Mehr Infos

Listing 3: Ausgabefunktion nutzen

function ausgeben(woher, y)
{
document.writeln('<p>' + woher +
': Wert von x ist ' + y + '</p>');
}
function f1()
{
ausgeben('f1', x); /* 5 */
x = 10;
ausgeben('f1', x); /* 10 */
}
function f2()
{
ausgeben('f2', x); /* undefined */
var x = 15;
ausgeben('f2', x); /* 15 */
}
var x = 5;
ausgeben('global', x); /* 5 */
f1();
ausgeben('global', x); /* 10 */
/* f1() hat den Wert von x veraendert */
f2();
ausgeben('global', x); /* 10 */
/* f1() hat lokales x verwendet */
/* globales x ist unveraendert */

Objekte spielen in Javascript die entscheidende Rolle. Ihr Modell basiert auf Prototypen, das heißt auf Basis eines vorhandenen Objekts lassen sich weitere Instanzen (neue Objekte) durch Aufruf einer Konstruktor-Funktion durch den Operators new bilden:

meinObjekt = new makeMeinObjekt(); 

new erzeugt die neue Instanz, und die Konstruktor-Funktion makeMeinObjekt() sorgt dafür, dass das Objekt die erforderlichen Eigenschaften und Methoden erhält.

Javascript kennt eine Reihe von Objekten, für die die Sprache schon einen Prototyp und die zugehörige Konstruktor-Funktion mitbringt (Native Ecmascript Objects). Dazu gehören Array, Boolean, Date, Number, RegExp und String. Will man derartige Objekte verwenden, muss man sich nicht um eine passende Konstruktor-Funktion kümmern. Ein Date-Objekt lässt sich damit leicht anlegen und durch Übergabe von Parametern nach Wunsch initialisieren.

/* Aktuelles Datum mit Uhrzeit */
heute = new Date();
/* 1. Januar 1970 0:00 Uhr */
StundeNull = new Date(0);
/* 24.12.2003 18:00 */
Bescherung = new Date(2003,11,24,18,0,0);

Im Ergebnis besitzen die neuen Objekte alle Eigenschaften und Methoden des Date-Objekts. Ist das in Listing 4 stehende Script in den Body eines HTML-Dokuments eingebaut, generiert es einen Absatz (p), der darüber informiert, der wie vielte Tag welchen Jahres heute ist. Es verwendet dazu unter anderem die Methoden setFullYear() und getTime() der zuvor angelegten Objekte Neujahr und heute.

Mehr Infos

Listing 4: Formularüberprüfung

<html>
<head>
<title>Formularprüfung</title>
<script language="Javascript"
type="text/javascript">
function istZahl(form)
{
var test = parseFloat(form.num.value);
if(!isNaN(test))
// true bewirkt, dass submit ausgefuehrt wird
return true;
alert("Bitte nur numerische Eingaben!")
// false verhindert submit
return false;
}
</script>
</head>
<body>
<form onsubmit="istZahl(this)">
<p>Eingabe (numerisch):
<input type="text" name="num"></p>
<p><input type="submit"
value="Abschicken"></p>
</form>
</body>
</html>

Ähnlich wie bei Date kann man Instanzen der anderen Objekte erzeugen, ihre Eigenschaften und Methoden verwenden.

neuerString = new String(); 

definiert ein String-Objekt. Der Vollständigkeit halber sei erwähnt, dass es nur auf diese Weise definiert werden kann. Auch wenn dessen Methoden scheinbar für einfache Werte vom Typ string existieren, handelt es sich nicht um String-Objekte. meineSprache und deineSprache in folgendem Code verhalten sich rein äußerlich vollkommen identisch; sie sind es jedoch nicht. Der typeof-Operator bringt es ans Licht: meineSprache ist vom Typ string, deineSprache vom Typ object.

meineSprache = 'Javascript';
deineSprache = new String('Javascript');
alert (meineSprache.toUpperCase() + ' '
+ deineSprache.toUpperCase());
alert (meineSprache.charAt(4) + ' '
+ deineSprache.charAt(4));
alert (typeof meineSprache + ' '
+ typeof deineSprache);

Der Grund dafür, dass die Methoden sich auf einfache Werte anwenden lassen, liegt darin, dass Javascript temporär dafür ein umhüllendes Objekt (Wrapper) anlegt.

Dieser Unterschied mag akademisch anmuten - er ist es aber nicht. Einem echten String-Objekt kann man wie anderen Objekten Eigenschaften hinzufügen (siehe unten), dem einfachen Wert vom Typ string nur scheinbar.

meineSprache.neueEigenschaft = 'neu'; 
deineSprache.neueEigenschaft = 'neu';
alert (meineSprache.neueEigenschaft + ' '
+deineSprache.neueEigenschaft);

Solche Anweisungen führen zu keinem Fehler. Im Ergebnis jedoch hat deineSprache tatsächlich den Wert „neu“, der Wert von meineSprache ist aber „undefined“.

Eine gewisse Sonderrolle spielt das Math-Objekt, das zwar vordefiniert vorhanden ist, für das jedoch keine Konstruktor-Funktion existiert, mit deren Hilfe man eine weitere Instanz definieren könnte.

Ein Objekt, das in kaum einem Script fehlt, ist Array. Es handelt sich ebenfalls um ein natives Ecmascript-Objekt, eine Sammlung „beliebiger“ Werte, die ein Script einzeln über den numerischen Index ansprechen kann. Diese Werte müssen nicht vom selben Typ sein, eine Mischung aus Integer-Zahlen und Zeichenketten ist erlaubt:

Feld = new Array('ein Text', 17, new Date());
for (var i=0; i<Feld.length; i++)
alert('Element ' + i +
' - Typ: ' + typeof Feld[i] +
' - Wert: ' + Feld[i] + ' ' )

In der Praxis dürften Arrays meist aus Elementen desselben Typs bestehen. Oben stehender Code, der Konstruktor-Funktion gleich die Werte für die Array-Elemente mitzuteilen, ist eine Variante, ein Array zu definieren. Eine andere legt zunächst das Objekt an und füllt es anschließend mit Elementen.

Monate = new Array();
for (var i = 0; i < 12; i++)
Monate[i] = i + 1;

Außer solch eindimensionalen lassen sich mehrdimensionale Arrays definieren, wie in Listing 5 demonstriert.

Mehr Infos

Listing 5: Datumsobjekt

heute = new Date()
Neujahr = new Date(1995,0,1,0,0,0,0); /* 01.01.19995 */
Neujahr.setFullYear(heute.getFullYear()); /* laufendes Jahr */
msProTag = 24 * 60 * 60 * 1000 /* Millisekunden pro Tag */
Tag = (heute.getTime() - Neujahr.getTime()) / msProTag;
Tag = Math.ceil(Tag); /* kleinste ganze Zahl >= Argument */
document.write('<p>Heute ist der ' + Tag
+ '. Tag des Jahres ' + heute.getFullYear()
+ '.</p>');

Für die bisher definierten Objekte brachte Javascript die notwendigen Werkzeuge Prototyp und Konstruktor-Funktion schon mit. Will man eigene Objekte mit eigenen Eigenschaften und Methoden definieren, muss man sich um die Werkzeuge selbst kümmern. So könnte die Konstruktor-Funktion für einen Objekttyp Artikel und ihre Verwendung zur Bildung einer neuen Instanz so aussehen:

function makeArtikel(pAutor, pHeft, pTitel) 
{
this.Autor = pAutor;
this.Titel = pTitel;
this.Heft = pHeft;
}
Artikel = new makeArtikel("Stefan Mintert",
"iX 10/98",
"Babylon-News - Javascript-Version 1.3");

Wichtig ist hier das Keyword this. Es weist grundsätzlich auf das Objekt selbst. Die Funktion definiert damit in diesem Fall drei Eigenschaften für das Objekt (in diesem Fall Autor, Titel und Heft) und initialisiert deren Werte mit denen der übergebenen Parameter. Artikel.Heft hat anschließend den Wert „iX 10/98“. Methoden werden ganz ähnlich hinzugefügt; indem man ihnen Referenzen auf Funktionen zuweist. In Listing 6 erhält das Objekt Liste eine Methode eintragen. Wie das Listing zeigt, lassen sich vorgefertigte Objekte (hier das Array Liste) ebenfalls um Eigenschaften und Methoden erweitern.

Mehr Infos

Listing 6: Mehrdimensionales Array

var Ausgabe = '<table border="1">';
var Schachbrett = new Array();
for (var i = 0; i < 8; i++)
{
Schachbrett[i] = new Array();
for (var j = 0; j < 8; j++)
if ((i + j)%2 == 0)
Schachbrett[i][j] = 'w';
else
Schachbrett[i][j] = 's';
}
for (var i = 0; i < Schachbrett.length; i++)
{
Ausgabe += '<tr>';
for (var j = 0; j < Schachbrett[i].length; j++)
Ausgabe += '<td align="center">'
+ Schachbrett[i][j] + '<\/td>';
Ausgabe += '<\/tr>';
}
Ausgabe += '<\/table>';
document.write(Ausgabe);

Das Objekt Liste enthält die Methode fEintragen zugewiesen, die die Literaturangaben der nebenstehenden Abbildung erzeugt.

Ein Objekt mit Sonderrolle sei noch erwähnt: das globale aus der Sicht von Ecmascript. Es bildet sozusagen den äußeren Rahmen, nimmt alle globalen Variablen und Funktionen auf. Wie es konkret aussieht, ist abhängig von der Umgebung, in der Ecmascript läuft, und damit von der konkreten Implementierung. In den vorhandenen Browsern ist es das Fensterobjekt (window). Variablen, Funktionen, Objekte et cetera, die nicht explizit in einem anderen Scope definiert werden, gehören damit dem Fensterobjekt.

var meineVariable = 'mein Text'; 
function meineFunktion() {}
alert(meineVariable + ' - ' + meineFunktion.name + '\n' +
window.meineVariable + ' - ' + window.meineFunktion.name);

Globale Variablen sind in Browsern auch über window ansprechbar.

Wie das Ergebnis zeigt (siehe Abbildung oben), ist meineVariable mit window.meineVariable und meineFunktion mit window.meineFunktion identisch.

Im nächsten Teil des Tutorials geht es darum, wie Javascript auf Webdokumente und deren Elemente zugreifen kann und Inhalte beziehungsweise Darstellung sich beeinflussen lassen. Das DOM des W3C und der praktische Umgang damit spielen dabei die zentrale Rolle.

Christine Kühnel
ist freiberuflich im Bereich Webdesign tätig und beschäftigt sich intensiv mit Webstandards, nicht nur denen des W3C.

[1] Stefan Mintert, Christine Kühnel; JavaScript Workshop, München (Addison-Wesley) 2000; javascript-workshop.de/

[2] Christine Kühnel, Stefan Mintert: JavaScript revisited iX 10/2000, S. 34

[3] Cai Ziegler; JavaScript-Know-how; Gralssuche; JavaScript und Objektorientierung; iX 4/2001, S. 194

[4] Georg Maaß; Projekt 10K - The DHTML Tutorial; gml-modul.sourceforge.net/cgi-bin/gmL/?domain=DHTML-Tutorial&webpage=1

Mehr Infos

iX-TRACT

  • Der Dschungel der Objektmodelle lichtet sich: Nicht mehr jeder Browser enthält ein eigenes Modell, sondern das des W3C setzt sich durch.
  • Javascript ist eine auf Prototypen basierende Sprache: Auf Basis eines vorhandenen Objekts lassen sich weitere Instanzen durch new Auto et cetera bilden.
  • Eine Reihe von Objekten sind in Javascript schon vorhanden (wie Date), weitere kann sich jeder definieren.
Mehr Infos

Tutorial-Übersicht

Teil 1: Elemente der Sprache Javascript (Ecmascript), mit Objekten arbeiten, eigene Objekte definieren

Teil 2: Manipulation von Webdokumenten mit dem Document Object Model (DOM) des W3C

Teil 3: Javascript in der Browserumgebung, sinnvoller Einsatz von Javascript im Web

Download der Listings (hb)