Anzeige
Tutorialbeschreibung

Basiswissen JavaScript/DOM Teil2a - Sprachkonzepte von JavaScript

Basiswissen JavaScript/DOM Teil2a - Sprachkonzepte von JavaScript

JavaScript ist eine Programmiersprache, die sich ähnlich wie CSS in HTML integrieren lässt und wie CSS vom Browser ausgeführt wird. Sie erlaubt während der Anzeige einer Webseite beim Anwender dynamische Änderungen am Inhalt und Erscheinungsbild der Seite sowie einfache Benutzerinteraktion. Das Document Object Model (DOM) ist dabei der Standard für den dynamischen Zugriff auf HTML-Elemente, für die Steuerung von Anwenderereignissen usw.


Das nun folgende Tutorial ist ein Auszug aus dem Buch: Professionelle Websites von Stefan Münz.
Die Veröffentlichung des Kapitels erfolgt mit freundlicher Genehmigung von Pearson Education .


3 Sprachkonzepte von JavaScript


Im vorherigen Abschnitt konzentrierten wir uns auf die möglichen Orte von JavaScript- Code und auf das Zusammenspiel zwischen HTML und JavaScript. In diesem Abschnitt geht es nun darum, die syntaktischen Details und Potenziale von JavaScript zu verstehen und anzuwenden.

3.1 Allgemeines zur Code-Erstellung

Bevor wir auf die einzelnen syntaktischen Bestandteile von JavaScript eingehen, seien noch ein paar Bemerkungen zur »Philosophie« beim Erstellen von Script-Code gemacht.
Die meisten Programmierer legen sich im Laufe der Zeit einen eigenen Programmierstil zu. Einige bemühen sich, ihren Code so schwer wie möglich nachvollziehbar zu machen, in der meist uneingestandenen und leider oftmals erfüllten Hoffnung, von Anfängern dafür bewundert zu werden und als Guru zu gelten.

Professionell ist das jedoch nicht. Bei professionellem Programmcode steht die Forderung nach Transparenz an oberster Stelle. Dafür gibt es Gründe:

- Wenn ein Programmierer selbst nach Monaten oder gar Jahren ein Script ändern, korrigieren oder optimieren soll, kann er sich in der Regel nicht mehr an alle Einzelheiten des Scriptaufbaus, der gewählten Problemlösungsstrategien usw. erinnern. Je transparenter das Script diese Aspekte jedoch offenbart, desto leichter ist es für den Programmierer, schnell wieder in das Script »hineinzufinden«.
- Scripts werden bei größeren Projekten oftmals auch von anderen Programmierern weiter gepflegt. Jeder Programmierer weiß, dass es nicht einfach ist, sich in fremde Konzepte, Denkstrategien usw. hineinzudenken. Je transparenter das Script in dieser Hinsicht jedoch ist, desto einfacher ist es für andere, Code nachzuvollziehen.
- Teile von Scripts, insbesondere Funktionen, aber auch Datenstrukturen, werden oftmals in anderen Projekten wiederverwendet. Deshalb ist es beim Erstellen von Code sinnvoll, gleich darauf zu achten, dass Code-Teile geschlossen wiederverwendbar sind.

Lesbarkeit
Zur guten Lesbarkeit von Code gehört eine ordentliche Formatierung. Trennen Sie beispielsweise mehrere Funktionen durch eine oder mehrere Leerzeilen voneinander, damit leichter erkennbar ist, wo eine Funktion beginnt und wo sie aufhört. Dem JavaScript- Interpreter ist dies egal – er findet beispielsweise blitzschnell Funktionsblöcke. Der menschliche »Code-Leser« tut sich dabei jedoch deutlich schwerer.
Notieren Sie jede neue Anweisung so weit sinnvoll in einer neuen Zeile. Auch wenn der JavaScript- Interpreter Anweisungen am schließenden Semikolon voneinander trennt, so ist es einfach besser lesbar, wenn Anweisungen wie in klassischen, zeilenorientierten Programmiersprachen zeilenweise notiert sind.
Arbeiten Sie mit Einrückungen. Der Inhalt etwa einer Funktion sollte gegenüber der Funktionsdeklaration um zwei bis vier Zeichen eingerückt sein. Ebenso verhält es sich beim Arbeiten mit Kontrollstrukturen.

Einheitlichkeit
Gewöhnen Sie sich beispielsweise bei der Vergabe von Variablen- und Funktionsnamen ein einheitliches Schema an. Im vorliegenden Buch verwenden wir beispielsweise nur englischsprachige Namen, die ausschließlich klein geschrieben sind und bei denen im Fall mehrerer Namensteile Unterstriche das Leseverständnis erhöhen. Wir verwenden auch keine schwer zu erratenden Abkürzungen.
Es spricht nichts gegen andere Prinzipien, z.B. die Verwendung deutschsprachiger Namen mit anderen Regeln für Klein- und Großschreibung. Kryptisch wird der Code jedoch dann, wenn mal so, mal so gearbeitet wird.

Kommentare

Sparen Sie nicht damit, Code in Kommentaren zu dokumentieren. Auch für die optische Trennung und Einleitung von Code-Abschnitten werden Kommentare gern genutzt.
Dazu als Beispiel noch mal unsere Funktion show_date() aus Abschnitt 7.2.3. In diesem Fall wird die Funktion jedoch um verschiedene Kommentare ergänzt. Die Kommentare werden vom JavaScript-Interpreter ignoriert, erleichtern Menschen jedoch das Verständnis des Codes:

Listing 7.5: Funktion mit JavaScript-Kommentaren

Bilder

JavaScript-Kommentare beginnen entweder mit zwei Schrägstrichen //. In diesem Fall gilt alles, was danach bis zum Zeilenende folgt, als Kommentar. Oder ein Kommentar wird in der Form /* ... */ notiert. Alles, was zwischen /* und */ notiert wird, gilt dann als Kommentar.
Im Beispiel werden Kommentare für unterschiedliche Zwecke eingesetzt:

- Oberhalb der Funktion wird durch Kommentare ein optisch hervorgehobener Bereich erzeugt, der die Aufgabe und den korrekten Aufruf der Funktion dokumentiert.
- Innerhalb der Funktion werden einzelnen, sich möglicherweise nicht unmittelbar erschließenden Anweisungen erläuternde Kommentare vorangestellt.
- Unten in der Funktion wird ein alternatives Code-Fragment durch Kommentar ausgeklammert.

Da JavaScripts selbst in Großprojekten nicht so strikt dokumentiert werden wie Softwareentwicklung, bleiben die Kommentare im Script meist die einzige zum Script existierende Dokumentation. Entsprechend ernst sollte dieses Feature vor allem bei nicht trivialen Scripts genommen werden.

3.2 Anweisungen, Ausdrücke und Blöcke

JavaScript besteht wie jede Programmiersprache aus einer kontrollierten Abfolge von Anweisungen. Gewöhnen Sie sich am besten gleich an, jede Anweisung durch ein Semikolon abzuschließen. Das ursprüngliche Netscape-JavaScript erlaubt es zwar auch, Anweisungen einfach durch Zeilenumbruch zu trennen. Doch um Fehler zu vermeiden, ist dringend zu empfehlen, davon keinen Gebrauch zu machen. Nur in einem Fall kann das Semikolon bedenkenlos weggelassen werden: wenn in der Wertzuweisung an einen Event-Handler nur eine einzige Anweisung notiert wird, wie z.B. onLoad="show_date()".

Anweisungen und Ausdrücke
»Anweisung« ist ein Oberbegriff. Bei Anweisungen, die als Ergebnis einen Wert produziert, spricht man auch von »Ausdruck«.

Dazu folgendes Beispiel:

x = 3 + 5;
document.write(x);

Das Beispiel besteht aus zwei Anweisungen. Die erste davon ist jedoch ein Ausdruck, da in diesem Fall ein Wert produziert wird. Die zweite Anweisung ist dagegen kein Ausdruck, weil in diesem Fall nur etwas geschieht, was aber keinen neuen Wert schafft.

Anweisungsblöcke
Blöcke aus mehreren Anweisungen und Ausdrücken werden in JavaScript in geschweifte Klammern { bzw. } eingeschlossen. Blöcke entstehen beispielsweise bei Funktionen. Alle Anweisungen einer Funktion werden deshalb von geschweiften Klammern umgeben. Aber auch, wenn mehrere Anweisungen von einer erfüllten Bedingung abhängen sollen, werden diese als Block mit geschweiften Klammern markiert. Es gibt noch mehr Situationen, in denen Blöcke vorkommen können. Wichtig ist zunächst nur zu wissen, dass Blöcke eine strukturelle Einheit aus mehreren Anweisungen bilden, markiert durch geschweifte Klammern. Anweisungsblöcke können auch ineinander verschachtelt sein.

3.3 Variablen und Datentypen in JavaScript

Werte, die sich ein Script zur späteren Verwendung merken muss, werden in Variablen gespeichert. Variablen sind benannte, reservierte Speicherplätze für bestimmte Daten.

Variablendeklaration ohne und mit Initialisierung
Es gehört zum sauberen Programmierstil, Variablen bei der ersten Erwähnung im Script zu deklarieren.

Dazu ein paar Beispiele:

var given_name;
var family_name = "Müller";
var x = 3 * (7 + 5);
var y = x / 2;
var datetime = get_datetime();

Variablen werden durch das Schlüsselwort var, gefolgt vom gewünschten Variablennamen, deklariert. Es genügt, die Variable erst einmal zu deklarieren, ohne ihr einen Wert zuzuweisen. In der ersten Beispielzeile wird eine solche Variable deklariert (die Variable given_name).

Alle anderen Beispielvariablen bekommen bei der Deklaration nach einem Gleichheitszeichen einen Wert zugewiesen. Diese anfängliche Wertzuweisung bezeichnet man als Initialisierung einer Variable. Die Wertzuweisung kann ein schlichter Wert sein, wie im Beispiel der Variablen family_name. Sie kann aber auch ein errechneter Wert sein, wie im Beispiel der Variablen x. In solchen Berechnungen können auch andere, bereits deklarierte Variablen vorkommen. So wird im Beispiel der Initialisierung von y mit x gerechnet. An die Stelle von x wird dabei deren aktueller Wert eingesetzt. Die Initialisierung kann aber auch wie im letzten Beispiel ein Funktionsaufruf sein. Voraussetzung ist, dass die Funktion einen Wert ermittelt und zurückgibt.

Bei der Initialisierung und auch bei weiteren Wertänderungen von Variablen im Verlauf des Scripts brauchen Sie sich nicht um die Arbeitsspeicherreservierung zu kümmern. Sie haben aus Sicherheitsgründen auch gar keine Einflussmöglichkeit darauf. Die gesamte Speicherverwaltung übernimmt der JavaScript-Interpreter selbst.

Globale und lokale Variablen
Variablen, die in einem script-Bereich oder in einer JavaScript-Datei außerhalb einer Funktion deklariert werden, sind globale Variablen. Auf sie kann auch innerhalb von Funktionen zugegriffen werden. Variablen, die innerhalb einer Funktion deklariert werden, sind dagegen lokale Variablen, deren Gültigkeit und Bekanntheit sich auf die Funktion beschränkt.

Konventionen bei Variablennamen
Variablennamen in JavaScript dürfen aus den Großbuchstaben A bis Z, den Kleinbuchstaben a bis z, den Ziffern 0 bis 9 und dem Unterstrich (_) bestehen. Das erste Zeichen darf keine Ziffer sein. Buchstaben wie ä, ö, ü oder ß sind nicht erlaubt. Leerzeichen auch nicht. Die erlaubte Länge der Namen ist nicht explizit festgelegt, sollte aber aus praktischen Gründen die Größenordnung von ein paar Dutzend Zeichen nicht überschreiten. Variablennamen dürfen nicht mit einem reservierten Schlüsselwort von JavaScript identisch sein. Das betrifft folgende Wörter:

abstract, boolean, break, byte, case, catch, char, class, const, continue, debugger, default, delete, delete, do, double, else, enum, export, export, extends, final, finally, float, for, function, goto, if, implements, import, import, in, instanceof, int, interface, long, native, new, null, package, private, protected, public, public, return, short, static, super, switch, synchronized, this, throw, throws, transient, true, try, typeof, var, void, volatile, while, with.

Einige der Schlüsselwörter werden gegenwärtig von JavaScript gar nicht verwendet, sind jedoch für künftige Zwecke reserviert und gehören daher mit zu den zu vermeidenden Variablennamen.

Gültige Variablennamen sind also beispielsweise:

Name
nick_name
name2
a
_a
p101260

Ungültige Variablennamen (führen zu Fehlern) sind beispielsweise:

Übergröße (nicht erlaubte Buchstaben)
1a (Ziffer als erstes Zeichen)
family name (Leerzeichen)
true (reserviertes Wort)

Datentypen und Typumwandlung
Wie praktisch alle Programmiersprachen unterscheidet auch JavaScript zwischen verschiedenen Datentypen. Der Grund ist, dass etwa Zeichenketten und Zahlen intern im Arbeitsspeicher unterschiedlich gespeichert werden. Damit der JavaScript-Interpreter einen gespeicherten Variablenwert korrekt aus dem Speicher ausgelesen kann, muss er wissen, nach welchem Datentyp der Wert zu behandeln ist.
Bei der Wertzuweisung an eine Variable entscheiden Sie durch die Notationsweise, welchen Datentyp Sie meinen. Das folgende Beispiel zeigt den Unterschied:

var x = 36;
var y = "36";

Zeichenkettenwerte werden in hohe Anführungszeichen gesetzt, Zahlen dagegen nicht. Bei den Anführungszeichen von Zeichenketten sind sowohl doppelte als auch einfache Anführungszeichen erlaubt. Beide die Zeichenkette einschließenden Zeichen müssen jedoch gleich sein.
In der obigen Beispielvariable x ist also nach der Initialisierung der numerische Wert 36 gespeichert und in y die Zeichenkette 36.

Mit x können Sie anschließend rechnen, z.B. z = Math.sqrt(x), was in Variable z die Quadratwurzel aus 36 speichert. Wenn Sie z = Math.sqrt(y) notieren, wird jedoch ebenfalls 6 errechnet. Anstatt einen Typfehler zu produzieren, nimmt der JavaScript-Interpreter in lösbaren Konfliktsituationen eine automatische Typumwandlung vor. Da im Beispiel das Rechnen mit einer Zeichenkette verlangt wird und deren Wert sich als gültige Zahl interpretieren lässt, interpretiert es der JavaScript-Interpreter ohne Rückfrage tatsächlich so.

Mit y können Sie dagegen Zeichenkettenoperationen durchführen. Auf jede Zeichenkettenvariable in JavaScript ist unter anderem die Eigenschaft length anwendbar, welche die Anzahl Zeichen der Zeichenkette ermittelt. Wenn Sie document.write(y.length) notieren, schreibt der Browser den Wert 2 ins Dokument, weil in y der Wert 36 als Zeichenkette gespeichert ist und diese Zeichenkette aus zwei Zeichen besteht.

Wenn Sie document.write(x.length) notieren, wenden Sie eine Zeichenketteneigenschaft auf einen numerisch gespeicherten Wert an. In diesem Fall nimmt der JavaScript-Interpreter jedoch keine automatische Typkonvertierung vor, sondern schreibt »undefined« ins Dokument.

Um sich nicht auf die automatische Typumwandlung zu verlassen, können Sie eine Typumwandlung auch explizit erzwingen. Wichtig ist dabei natürlich, dass die Umwandlung lösbar ist. Wenn Sie etwa document.write(String(x).length) notieren und in x der numerische Wert 36 gespeichert ist, schreibt JavaScript den Wert 2 ins Dokument. Grund dafür ist die globale JavaScript-Funktion String(), die dafür sorgt, dass ein Wert auf jeden Fall als Zeichenkette behandelt wird. Das Konstrukt String(x) bedeutet so viel wie »behandle den Wert von x als Zeichenkette«. Kombiniert mit der Zeichenketteneigenschaft length ergibt sich ein Wert von 2, da 36 als Zeichenkette betrachtet aus zwei Zeichen besteht.

Nachfolgende Tabelle listet globale JavaScript-Funktionen zur Typumwandlung auf.

Bilder

Die Notwendigkeit expliziter Typumwandlungen mag zunächst etwas abstrakt erscheinen. Ein gutes Beispiel aus der Praxis ist das Einlesen von Inhalten aus Formularfeldern. Funktion Bedeutung Greift ein JavaScript auf eine Zahl zu, die ein Anwender in einem HTML-Formular eingegeben hat, so liegt der ausgelesene Wert zunächst als Zeichenkette vor. Soll mit dem Wert gerechnet werden, ist eine Typumwandlung in vielen Fällen erforderlich.

Ganzzahlen (Integer) und Fließkommazahlen (Float)
Bei numerischen Werten wird zwischen Ganzzahlen und Fließkommazahlen unterschieden. Der Grund ist auch hier ein Unterschied in der internen Speicherung im Arbeitsspeicher.
Integer-Werte belegen 4 »Octets«, also 4 Einheiten zu je 8 Bit im Arbeitsspeicher. Da es positive und negative Ganzzahlen gibt, wird ein Bit für die Speicherung des Vorzeichens (+ oder –) benötigt. Bleiben 31 Bit für die Zahl. Damit lassen sich 2.147.483.647 (ca. 2,1 Milliarden) unterschiedliche Werte speichern. Der Wertebereich von Integer-Ganzzahlen reicht demnach von –2.147.483.647 bis 2.147.483.647. Das sind 4.294.967.295 unterschiedliche Zahlen.
Bei Zahlen, die größer oder kleiner sind, verwendet der JavaScript-Interpreter automatisch eine Speicherung als Float-Zahl. Float-Zahlen können Sie jedoch auch explizit notieren, indem Sie »Kommazahlen« notieren. Das »Komma« ist in JavaScript allerdings der Punkt.

Falsch ist beispielsweise:

var x = 9,81;
Richtig ist:
var x = 9.81;

Der Speicheralgorithmus von Fließkommazahlen ist komplexer (er wird im Standard IEEE754 beschrieben). Der Ausdruck »Fließkomma« (»Gleitpunkt« meint das Gleiche) drückt jedoch gut aus, was passiert: Je kleiner der Ganzzahlanteil einer Float-Zahl ist, desto mehr Nachkommastellen können gespeichert werden. Je größer dagegen der Ganzzahlanteil, desto weniger Nachkommastellen können gespeichert werden. Fließkommawerte können also »unscharf« werden.

Negative Zahlen bekommen in JavaScript wie üblich ein Minuszeichen vorangestellt. Das gilt sowohl für Integer-Zahlen als auch für Float-Zahlen.

Boolean-Werte
Ein Boolean-Wert ist ein ja/nein-Wert. Er kann nur die Werte 1 oder 0 haben und lässt sich auch durch die reservierten Wörter true (wahr) und false (falsch) ausdrücken. Diese Werte können Sie beispielsweise bei der Variableninitialisierung zuweisen:

var play_the_game = false;
var show_help = true;

Sehr zweckmäßig sind Boolean-Werte bei Abfragen wie:

if(show_help == true)
document.getElementById("help").innerHTML = help_html;

Oder noch einfacher:

if(show_help)
document.getElementById("help").innerHTML = help_html;

Entsprechend bei false-Werten:

if(play_the_gabe == false)
highscore = 0;

Oder noch einfacher:

if(! play_the_game)
highscore = 0;

Auf die Syntax von if-Abfragen und Operatoren wie den Verneinungsoperator ! gehen wir später noch ein.
Auch Checkboxen und Radiobuttons aus HTML, die ja typische ja/nein-Schalter darstellen, stellen in JavaScript Boolean-Werte dar.
Rein technisch gesehen ist ein Boolean einfach eine Zahl. Jede numerische Variable, welche die Werte 1 oder 0 enthält, enthält damit automatisch auch die Boolean-Werte true bzw. false. Umgekehrt ist eine als Boolean-Wert initialisierte Variable immer auch eine normale Zahl, wie das folgende Beispiel zeigt:

var x = true;
x = x + 19;
document.write(x);

Das Beispiel schreibt den Wert 20 ins Browser-Fenster. Die Variable x wird mit true, also 1, initialisiert. Anschließend wird ihrem bisherigen Wert 19 hinzuaddiert.
Boolean-Variablen können auch mithilfe des Boolean-Objekts von JavaScript initialisiert werden.

Beispiele:

var do_it = new Boolean(true);
var do_not_do_it = new Boolean(false);

Es werden zwei Variablen definiert, die im Beispiel die namen do_it und do_not_do_it erhalten. Beide Variablen werden mit einem Aufruf der Funktion zum Erstellen einer neuen Instanz des Boolean-Objekts aufgerufen (new Boolean()). Dieser Funktion wird der gewünschte Initialwert true oder false übergeben.

Escape-Sequenzen für Steuerzeichen, Sonderzeichen und Maskierung
Bei Zeichenketten können Zeichen in Form von so genannten Escape-Sequenzen notiert werden. Das betrifft vor allem Steuerzeichen wie Zeilenvorschub oder Tabulator, aber auch Zeichen aus erweiterten Zeichenvorräten wie dem Latin-1-Zeichensatz oder dem Unicode-System, und schließlich jene Zeichen, die in JavaScript innerhalb von Zeichenketten besondere Bedeutung haben. Die nachfolgende Tabelle listet mögliche Escape-Sequenzen auf.

Bilder


Für Zeichenketten, die als HTML ausgegeben werden sollen, sind einige dieser Sequenzen uninteressant. Sonderzeichen sollten in solchen Zeichenketten in den Notationsformen erscheinen, die in HTML vorgesehen sind. Sehr häufig werden Sie dagegen die Escape- Sequenzen zum Maskieren benötigen.
Dazu ein Beispiel:

document.write
("<a href="http://www.example.org/">Beispiel-Link</a>");

Wenn Sie direkt mit document.write() HTML-Code in ein HTML-Dokument schreiben, müssen Sie die Zeichenkette, die der HTML-Code darstellt, wahlweise in doppelte oder in einfache hohe Anführungszeichen einschließen. Enthält die Zeichenkette eines der Zeichen, die zum Einschließen der Zeichenkette verwendet werden, muss es maskiert werden. Andernfalls würde der JavaScript- Interpreter das Ende der Zeichenkette vermuten und den Rest als ungültiges JavaScript mit einem Fehler quittieren. Im obigen Beispiel sind daher die Anführungszeichen der Wertzuweisung an das href-Attribut maskiert.

Nicht maskieren müssen Sie die "-Zeichen im folgenden Fall:

document.write
('<a href="http://www.example.org/">Beispiel-Link</a>');

In diesem Fall wird die Zeichenkette in einfache hohe Anführungszeichen eingeschlossen. Darin vorkommende doppelte Anführungszeichen sind dann nicht maskierungspflichtig.

Oktalnotation, Hexadezimalnotation und Potenzschreibweise von Zahlen
Ebenso wie Zeichen können auch Zahlen anders geschrieben werden als in der für Menschen am besten lesbaren Dezimalschreibweise.

Dazu ein Beispiel:

var x = 0x80 + 040 + 1.7E2;
document.write(x);

Bei diesem Beispiel schreibt der Browser am Ende den Wert 330 ins Dokument. Die Variable x bekommt bei der Initialisierung eine Addition von drei Zahlen zugewiesen. Die erste Zahl ist in Hexadezimalschreibweise notiert. Solche Notationen beginnen mit 0x, gefolgt von den Ziffern der Zahl. Erlaubt sind als Ziffern 0 bis 9 und A bis F (oder a bis f), wobei die Buchstaben den Dezimalwerten 10 bis 15 entsprechen. 0x10 bedeutet dann so viel wie 16 usw.

Die zweite Zahl im Beispiel ist eine Oktalzahl (System zur Basis 8). Solche Zahlen dürfen nur aus den Ziffern 0 bis 7 bestehen. Markiert werden Oktalzahlen durch eine führende 0. Diese Eigenheit kann in der Praxis übrigens für Verwirrung sorgen: Jede Ganzzahl, die aus mehr als einer Ziffer besteht und mit einer Ziffer 0 beginnt, wird von JavaScript oktal interpretiert. Das kann zu unerwarteten Ergebnissen führen, wenn JavaScript als Input eine »formatierte Zahl« mit führenden Nullen erhält und dann mit dieser Zahl gerechnet wird.

Die Potenzschreibweise schließlich ist vor allem bei sehr großen und sehr kleinen Gleitkommazahlen verbreitet. Mit e oder E bestimmen Sie die Zehnerpotenz bzw. die Anzahl Nullen, die hinter der Zahl vor dem e bzw. E stehen. 1.2e2 ist so viel wie 120, weil der Dezimalpunkt in Gedanken um zwei Stellen nach rechts verschoben wird, oder anders ausgedrückt, weil der Wert vor dem e mit 102, also mit 100, multipliziert wird. Durch Minuszeichen hinter dem e bzw. E wird der Dezimalpunkt dagegen nach links verschoben. 1.2e-2 entspricht 0.012.

3.4 Operatoren in JavaScript

Nachdem wir die etwas trockene Materie von Variablen und Werten hinter uns gebracht haben, steigen wir nun in den Bereich ein, der »typisch« ist für jedes Programmieren. Dazu gehören vor allem if-Abfragen, aber auch Schleifen und Fallunterscheidungen. Um sie zu realisieren, sind in vielen Fällen Operatoren erforderlich.

Ein Beispiel

Zum Warmwerden stellen wir ein typisches Praxisbeispiel vor. Darin soll der Anwender Text für eine SMS-Nachricht in ein Feld eingeben können. Die erforderliche Technik zum Versenden einer SMS über das Web muss natürlich serverseitig implementiert werden und soll hier nicht interessieren. Ein nützlicher Dienst, den JavaScript verrichten kann, ist jedoch, den Anwender während der Texteingabe jederzeit darüber zu informieren, wie viele Zeichen er noch eingeben kann. Denn die Länge von SMS-Nachrichten ist ja auf 160 Zeichen begrenzt.

Bilder

Das Beispiel ist so programmiert, dass bei jedem Tastendruck die fett angezeigte Zahl unterhalb des Eingabefelds aktualisiert wird. Beträgt der Restwert weiterer Zeichen 0, werden weitere eingegebene Zeichen einfach sofort wieder gelöscht und im Feld bleiben nur die ersten 160 Zeichen stehen.
Das input-Element im HTML-Formular enthält zu diesem Zweck einen Event-Handler onkeyup=. Dieser wird bei jedem Loslassen einer Taste ausgelöst. Dabei wird jedes Mal die Funktion check_input() aufgerufen, die in einem script-Bereich im Kopfteil des HTMLDokuments notiert ist.

Bilder

Abbildung 7.5: JavaScript-Überprüfung bei Benutzereingabe

In dieser Funktion kommen einige Operatoren und eine Kontrollstruktur vor. Der Funktionsinhalt beginnt mit einer if-Abfrage. Eine solche Abfrage gehört zu den Kontrollstrukturen. Bei jeder if-Abfrage muss eine Bedingung formuliert werden. Der JavaScript- Interpreter prüft die Bedingung und entscheidet, ob sie wahr oder falsch ist. Wenn sie wahr ist, werden die Anweisungen ausgeführt, die im Zweig unterhalb der if-Abfrage notiert sind. Sollen mehrere Anweisungen abhängig davon ausgeführt werden, müssen diese in geschweifte Klammern eingeschlossen werden. In unserem Beispiel soll bei erfüllter if-Bedingung jedoch nur eine Anweisung ausgeführt werden. In diesem Fall dürfen die geschweiften Klammern fehlen und es wird einfach die nächstnotierte Anweisung ausgeführt.

Im Beispiel wird folgende if-Abfrage formuliert:

if(document.getElementById(id_name).value.length > max_value)

Die zu prüfende Bedingung ist das, was innerhalb der Klammern von if() steht. Ein typischer Fall für das Formulieren einer Bedingung ist das Vergleichen von Werten. Im Beispiel besteht die Bedingungsfrage darin, ob die Zeichenanzahl (length) des Inhalt des Formularfelds (document.getElementById(id_name).value) größer ist als der Wert der Variablen max_value. Ein Wert für max_value wird der Funktion check_input() beim Aufruf übergeben.

In unserem Beispiel wird beim Funktionsaufruf im Event-Handler onkeyup= als Wert für max_value 160 übergeben. Angenommen, der Anwender hat bislang 10 Zeichen eingegeben, so dass als aktuelle Länge im Eingabefeld der Wert 10 ermittelt wird. Die if-Abfrage liest sich dann so:

if(10 > 160)

Was so viel bedeutet wie: »Wenn 10 größer als 160 ist, dann führe die nachfolgende Anweisung aus.« Der JavaScript-Interpreter kann diese Formulierung in jedem denkbaren Zustand eindeutig mit ja oder nein (»trifft zu« oder »trifft nicht zu«) beantworten. Und so führt er die bedingungsabhängige Anweisung entweder aus oder nicht.
Bei der Formulierung von Bedingungen kommen sehr häufig Operatoren zum Einsatz. Das >- Zeichen für »größer als« ist ein solcher Operator, ein Vergleichsoperator. Im Beispiel kommen aber auch noch andere Operatoren vor. Der gängigste davon ist sicherlich der bereits bekannte Zuweisungsoperator, ausgedrückt durch das Gleichheitszeichen =. Aber auch Rechenoperatoren gehören dazu. Die Funktion im Beispiel benutzt einen solchen Operator (den Subtraktionsoperator »-«), um den Inhalt des span-Elements mit dem id- Namen max zu aktualisieren. Der Rechenausdruck lautet:

max_value - document.getElementById(id_name).value.length

Vom maximal erlaubten Wert werden dabei die tatsächlich aktuell im Eingabefeld enthaltenen Zeichen abgezogen. Das Ergebnis ist die Anzahl der noch erlaubten Zeichen.
Ein weiterer Operator, der im Beispiel auftaucht, ist der void()-Operator im einleitenden <form>-Tag. Wir haben bereits früher erläutert, welchen Zweck diese Wertzuweisung an das action-Attribut hat. Vom Typ her ist void(), obwohl es wie eine Funktion aussieht, ein Operator. Seine Aufgabe besteht darin, zu verhindern, dass eine Operation einen Wert erzeugt.
Kontrollstrukturen und Operatoren sind also allgegenwärtig beim Programmieren. Insofern ist es wichtig, ihre Syntax und Eigenheiten genau zu kennen.

Vergleichsoperatoren
Vergleichsoperatoren werden vor allem zur Formulierung von Bedingungen in if-Abfragen oder Schleifen genutzt. Sie dienen dazu, zwei Werte zu vergleichen.

Bilder

Ein kleines Beispiel:

var browser = navigator.appName;
if(browser == "Netscape")
document.write("wirklich Netscape?");

Der Operator zur Prüfung auf Gleichheit zweier Werte darf nicht mit dem Zuweisungsoperator verwechselt werden. Hin und wieder unterläuft Programmierern der Fehler, dass sie ein Gleichheitszeichen vergessen und stattdessen eine Zuweisung formulieren anstelle eines Vergleichs. Wenn im obigen Beispiel etwa if(browser = "Netscape") notiert wäre, so wäre das aus syntaktischer Sicht nicht falsch, würde aber überraschende Ergebnisse liefern. Da die einfache Zuweisung immer wahr ist, ist das, was da als »Bedingung« formuliert wird, folglich auch immer wahr. Als Folge würde im Beispiel jeder Browser behaupten, er sei ein Netscape-Browser.
Auch bei einfachen Vergleichen von Werten greift in JavaScript die automatische Typumwandlung.

Ein Beispiel:

var x = 36;
var y = "36";
if(x == y)
document.write("beide Werte sind gleich");

Die Browser geben »beide Werte sind gleich« aus. Um genauer zu vergleichen, können Sie jedoch auch if(x === y) notieren. Dabei würde nicht auf Gleichheit erkannt, weil beide Variablen unterschiedlichen Typs sind.
Beim Operator != ist zu beachten, dass eine damit formulierte Bedingung dann wahr ist, wenn die Werte ungleich sind, und unwahr, wenn die Werte gleich sind.

Rechenoperatoren
Für die vier Grundrechenarten stehen in JavaScript die üblichen Operatoren zur Verfügung. Daneben gibt es noch den in vielen Programmiersprachen üblichen Modulo-Operator für Restwertdivision sowie einige verkürzte Notationsformen.

Bilder


Bei Rechenoperationen gilt die mathematisch übliche Punkt-vor-Strich-Regel, d.h., Multiplikation und Division haben Vorrang vor Addition und Subtraktion. Um die Regel zu beeinflussen, können Sie Klammern verwenden. 3 + 5 * 4 ergibt 23, weil zuerst multipliziert, dann addiert wird. Durch Notation von (3 + 5) * 4 wird 32 ermittelt, da die Klammer zuerst berechnet wird. Klammern können beliebig verschachtelt sein.
Der Modulo-Operator funktioniert folgendermaßen: 13 % 5 ergibt als Ergebnis 3, weil 13 / 5 ein Ganzzahlergebnis von 2 ergibt (10 / 5) und 3 übrig bleiben.
Die verkürzten Schreibweisen +=, -=, *= und /= haben sich in vielen Programmiersprachen etabliert, weil es häufig vorkommt, dass mit Variablen, ausgehend von ihrem aktuellen Wert, eine Rechenoperation durchgeführt werden soll.
Beispiel:

x = x + 3;

Dies kann verkürzt werden zu:

x += 3;

Wichtig ist, dass zwischen Operator und Gleichheitszeichen kein Leerzeichen steht.
Die beiden Operatoren für die so genannte Inkrementierung und Dekrementierung schließlich treten vor allem in Schleifen auf. Wir werden in Zusammenhang damit darauf zurückkommen.
Beim Rechnen mit JavaScript werden Sie möglicherweise einige Überraschungen erleben.

Ein Beispiel:

document.write(0.3 + 0.6);

Als Ergebnis schreibt der Browser beispielsweise 0.8999999999999999 ins Dokument. Dies sind jedoch keine Rechenfehler im engeren Sinn, sondern »Darstellungsfehler«. Intern wird mit Zahlen stets binär gerechnet. Bei Ausgaben von Zahlen, wie es etwa document. write() tut, muss der binär gespeicherte Wert jedoch in Dezimalschreibweise übertragen werden. Da aber, wie bereits erläutert wurde, gerade Float-Zahlen stets mit einer wertabhängigen Unschärfe gespeichert werden, überträgt sich diese Unschärfe auch bei der Übertragung in die Dezimaldarstellung.

In Abschnitt 7.3.9 gehen wir auf Lösungsmöglichkeiten für diese Probleme ein.

Logische Operatoren
In JavaScript gibt es zwei logische Verknüpfungen: »und« und »oder«. Verwendet werden sie beispielsweise zur Formulierung komplexer Bedingungen.

Zeichenfolge Bedeutung
&& Logische Und-Verknüpfung von zwei Ausdrücken. Beide Ausdrücke müssen wahr sein,
damit die gesamte Bedingung wahr ist. In allen anderen Fällen ist die gesamte Bedingung
nicht erfüllt.
|| Logische Oder-Verknüpfung von zwei Ausdrücken. Mindestens einer der Ausdrücke
muss wahr sein, damit die gesamte Bedingung wahr ist. Nur wenn keiner der Ausdrücke
wahr ist, ist die gesamte Bedingung nicht erfüllt.
Tabelle 7.6: Logische Operatoren in JavaScript

Ein Beispiel:

if(document.getElementById('city') == "München" &&
parseInt(document.getElementById('year_income')) < 20000)
comment = "Sie müssen wirklich sehr arm sein!";

Die Bedingung, die erfüllt sein muss, damit die angegebene Wertzuweisung an die Variable comment erfolgt, besteht aus zwei Bedingungen: Wenn in einem gedachten Formularelement mit id-Namen city der Wert München eingetragen wurde und wenn in einem anderen Formularelement als Jahresgehalt ein Wert von unter 20000 angegeben wurde, dann (und nur dann) ist die gesamte Bedingung erfüllt. Die beiden Einzelbedingungen bestehen darin, dass ein aus einem gedachten Formularelement gewonnener Wert mit einem bestimmten Wert durch Vergleichsoperatoren verglichen wird. Die logische Verknüpfung der Einzelbedingungen wird durch && erreicht.

Es lassen sich auch mehr als zwei Einzelbedingungen verknüpfen. Dabei dürfen logisches Und und logisches Oder auch gemischt werden. Dazu ist es wichtig zu wissen, dass von links nach rechts aufgelöst wird und im Zweifelsfall der Operator || Vorrang vor dem Operator && hat.

Dazu noch ein Beispiel:

var x = true;
var y = false;
var z = true;
if(x && y || x && z || y && z)
document.write("<p>das Ganze ist wahr</p>");
if(x || y && x || z && y || z)
document.write("<p>das Ganze ist wahr</p>");

In dem Beispiel werden drei Boolean-Variablen initialisiert. Dann folgen zwei komplexe Bedingungen in if-Abfragen.

Die erste zusammengesetzte Bedingung lautet im Klartext: »Wenn x und y beide wahr sind oder wenn x und z beide wahr sind oder wenn y und z beide wahr sind«. In diesem Fall ist das Ganze wahr. Da die Einzelbedingungen durch logisches Oder verknüpft werden, genügt es, wenn eine davon wahr ist, damit die gesamte Bedingung als wahr bewertet wird. Da die Einzelbedingung x && z wahr ist, weil beide Variablen den Boolean-Wert true haben und bei logischem Und bei beiden wahren Bedingungen die Gesamtbedingung wahr ist, ist auch die zusammengesetzte Bedingung der if-Abfrage wahr. Die document. write()-Anweisung wird daher ausgeführt.

Ebenso verhält es sich im zweiten Fall. Bewertet wird: »Wenn von x oder y eins wahr ist und wenn von x oder z eins wahr ist und wenn von y oder z eins wahr ist«. In diesem Fall ist das Ganze wahr. Da die Einzelbedingungen durch logisches Und miteinander verknüpft sind, müssen alle drei Einzelbedingungen wahr sein, damit das Ganze wahr ist. Von x oder y ist eins wahr, weil x = true. Von x oder z sind sogar beide wahr, weil x = true und z = true. Von y oder z ist eins wahr, weil z = true. Alle drei Einzelbedingungen sind wahr, also ist auch die gesamte Bedingung wahr.
Um die Bewertung zu beeinflussen, können Sie auch mit Klammern arbeiten.

Weitere Operatoren
JavaScript bietet noch eine ganze Reihe weiterer Operatoren an, darunter auch wie Funktionen aussehende Operatoren wie void(), typeof(), new(), delete() usw. Diese werden wir jedoch an anderen Stellen behandeln.

Wichtig ist noch der Negationsoperator, ausgedrückt durch ein einfaches !-Zeichen.

Ein Beispiel:

if(!document.getElementById)
return;

Das Konstrukt, wie es dort steht, werden wir später noch häufiger verwenden, um Browser auszuschließen, die kein DOM-fähiges JavaScript interpretieren. Im Beispiel wird abgefragt, ob der Browser ein bestimmtes Objekt, eine bestimmte Objektmethode oder Objekteigenschaft nicht kennt, in diesem Fall document.getElementById. Das Nicht wird dabei durch das voranstehende ! signalisiert.

Ebenfalls wissen sollten Sie, dass der Operator + nicht nur Zahlen, sondern auch Zeichenketten verknüpft.

Ein Beispiel:

var given_name = "Stefan";
var family_name = "Münz";
var name = given_name + " " + family_name;
document.write(name);

Im Beispiel werden bei der Initialisierung der Variablen name der Wert von given_name, ein Leerzeichen und der Wert von family_name über den Zeichenkettenoperator + zusammengesetzt.

Eine weitere Gruppe von Operatoren sind die so genannten Bit-Operatoren. Diese eignen sich zur Manipulation von einzelnen Zeichen oder Zahlen. Wegen der seltenen Verwendung und des umfangreichen nötigen Hintergrundwissens über binäre Speicherung gehen wir jedoch nicht näher darauf ein.

3.5 Kontrollstrukturen in JavaScript

Beispiele für einfache if-Abfragen haben wir bereits kennen gelernt. Solche Abfragen gehören zu den so genannten Kontrollstrukturen. Diese heißen so, weil sie Verzweigungsmöglichkeiten im Programmcode schaffen und weil sie es erlauben, Programmcode zu wiederholen.

if-Abfragen, if-else- und else-if-Konstrukte
Wenn die Bedingung einer if-Abfrage vom Scriptinterpreter als wahr bewertet wird, werden eine oder mehrere Anweisungen ausgeführt, die abhängig davon notiert sind. Mehrere Anweisungen müssen dabei als Block in geschweifte Klammern eingeschlossen werden.
Ein Beispiel:

if(attempt_count == 10) {
reset_game();
ask_for_new_game();
attempt_count = 0;
}

Das Beispiel könnte aus einem mit JavaScript realisierten Online-Spiel stammen. Der Anwender hat zehn Versuche, um ein Ziel zu erreichen. Bei jedem erfolglosen Versuch wird die Anzahl der Versuche um 1 hochgezählt. Bei zehn Versuchen soll abgebrochen werden. Die Variable zum Merken der Anzahl Versuche ist attempt_count. Die if-Abfrage prüft, ob die Variable den Wert 10 hat. Ist dies der Fall, werden drei durch geschweifte Klammern eingeschlossene Anweisungen ausgeführt, nämlich die Funktionsaufrufe reset_game() und ask_for_new_game() sowie das Zurücksetzen der Variablen attempt_count auf 0.

Oft soll aber nicht nur Code ausgeführt werden, wenn eine if-Bedingung wahr ist, sondern auch dann, wenn sie nicht wahr ist. Dazu gibt es das if-else-Konstrukt.
Wir erweitern unser Beispiel:

if(attempt_count == 10) {
reset_game();
ask_for_new_game();
attempt_count = 0;
}
else {
next_attempt();
attempt_count += 1;
}

Nun werden im Fall, dass attempt_count noch nicht den Wert 10 erreicht hat, ebenfalls zwei Anweisungen ausgeführt. Eine Funktion namens next_attempt() wird aufgerufen und der Zähler attempt_count wird um 1 erhöht. Der else-Zweig des if-else-Konstrukts wird also ausgeführt, egal ob attempt_count aktuell gerade bei 1 oder bei 4 oder 9 steht.

Noch einen Schritt weiter gehen Erweiterungen mit else if. Damit können weitere Bedingungen formuliert werden für den Fall, dass die Bedingungen zuvor nicht erfüllt sind.

Wir erweitern unser Beispiel abermals:

if(attempt_count == 10) {
reset_game();
ask_for_new_game();
attempt_count = 0;
}
else if(attempt_count == 9) {
warning_last_attempt();
next_attempt();
attempt_count += 1;
}
else {
next_attempt();
attempt_count += 1;
}

Zwischen if- und else-Zweig wird noch ein else-if-Zweig geschoben. Angenommen, der aktuelle Wert von attempt_count beträgt 9. In diesem Fall ist die Bedingung bei if nicht erfüllt. Die Bedingung, die hinter else if steht, ist jedoch erfüllt. Deshalb gelangt das Script in diesen Zweig und führt dessen Anweisungen aus. Im Beispiel unseres gedachten Spiels wird am Ende das Gleiche ausgeführt wie im else-Zweig. Zuvor wird jedoch noch eine Funktion namens warning_last_attempt() aufgerufen.

If- und else-Konstrukte können auch verschachtelt sein. Dazu folgendes Beispiel:

if(price >= 30000) {
if(year_income < 30000)
creditworthiness = "low";
else if(year_income < 50000)
creditworthiness = "medium";
else
creditworthiness = "high";
}

Dieses fiktive Beispiel nimmt an, dass ein Script einen vom Anwender gewünschten Kaufvorgang auswertet. Dabei werden der Kaufpreis der gewünschten Ware und das vom Anwender erfragte Jahreseinkommen in Beziehung gesetzt, um die Kreditwürdigkeit des Anwenders zu bewerten.

Die »äußere« if-Abfrage stellt eine Bedingung für den Kaufpreis auf. Wenn dieser mehr als 30000 beträgt, wird der Code innerhalb der geschweiften Klammern ausgeführt. In diesem Fall gelangt der Script-Interpreter in die »innere« if-Abfrage. Deren Bedingung besteht darin, dass das angegebene Jahreseinkommen weniger als 30000 beträgt. Dann wird die Variable creditworthiness auf low gesetzt. Ein else-if-Zweig und ein else-Zweig sorgen für weitere mögliche Wertzuweisungen.

Fallunterscheidung mit switch und case
Bilder

Fallunterscheidungen mit switch-case sind also immer dann sinnvoll, wenn Sie verschiedene mögliche Zustände einer Variablen unterscheiden und für jeden unterschiedenen Zustand individuellen Code ausführen möchten.
Die Syntax beginnt mit switch(Variablenname). Innerhalb geschweifter Klammern können beliebig viele Abarbeitungsmarken des Typs case Wert: gesetzt werden. Am Ende sollte eine Marke des Typs default: gesetzt werden, die alle Variablenzustände behandelt, welche nicht durch zuvor unterschiedene Fälle abgedeckt wurden. Abhängig von case: und default: können ein oder mehrere Anweisungen notiert werden. Zum sauberen Programmierstil gehört es, eine break-Anweisung am Ende jedes unterschiedenen Falls zu notieren. Dadurch wird der Scriptinterpreter angewiesen, das gesamte switch-Konstrukt zu verlassen, sobald ein Fall auf den aktuellen Variablenzustand zutrifft und die entsprechenden Anweisungen abgearbeitet wurden.

for-Schleifen und for-in-Schleifen
Schleifen mit dem Schlüsselwort for eignen sich, um Anweisungen in einer von vorneherein feststehenden Anzahl von Wiederholungen auszuführen.

Das folgende Beispiel zeigt einen typischen Anwendungsfall:

<script type="text/javascript">
var html = "<table border="1"><tr>";
for(i = 1; i <= 10; i++)
html += "<td>" + i + "</td>";
html += "</tr></table>";
document.write(html);
</script>

Bilder

Abbildung 7.6: Mit for-Schleife erzeugte HTML-Tabelle

Das Script in diesem Bereich errichtet eine kleine HTML-Tabelle, bestehend aus einer Zeile mit zehn Zellen. Jede Zelle erhält als Textinhalt den aktuellen Zählerwert. Das Beispiel ist auch insofern praxistypisch, als es zeigt, wie größere Mengen von HTML-Code nach und nach in einer Variablen gesammelt werden. Die Variable wird dann am Ende in einem einzigen Schritt ausgegeben. Das ist wesentlich sauberer, als mit etlichen document.write()- Anweisungen zu arbeiten.

Deklariert wird eine Variable namens html. Zur Initialisierung wird ihr gleich der HTMLCode für das einleitende <table>-Tag und das <tr>-Tag der Tabellenzeile als Zeichenkette zugewiesen. Dann folgt die for-Schleife, welche die zehn Zellen erzeugt. In den runden Klammern der for-Schleife sind drei Anweisungen notiert. Die erste initialisiert eine Variable; die zweite formuliert eine Durchlaufbedingung für die Schleife; die dritte verändert die Variable so, dass die Durchlaufbedingung irgendwann nicht mehr erfüllt ist und die Schleife abbricht.

Seit Generationen von Programmierern hat es sich eingebürgert, für eine typische Zählervariable den Namen i zu vergeben. In der ersten Anweisung des for-Schleifenkopfs wird im Beispiel eine Variable dieses Namens deklariert und mit dem Wert 1 initialisiert. In der mittleren Anweisung wird als Durchlaufbedingung für die Schleife i <= 10 formuliert. Die Schleife wird also durchlaufen, wenn i einen Wert kleiner oder gleich 10 hat. In der letzten Anweisung wird i inkrementiert, also um 1 hochgezählt.

Im Beispiel ist nur eine Anweisung vom Schleifenkopf abhängig. Wären es mehrere Anweisungen, müssten sie als Block in geschweifte Klammern eingeschlossen werden. Die abhängige Anweisung erweitert den Inhalt der Variablen html um den HTML-Code einer Tabellenzelle, als deren Textinhalt der aktuelle Wert von i eingefügt wird.
Bei jedem Schleifendurchlauf wird die Durchlaufbedingung erneut geprüft. Durch die Inkrementierung nimmt i nach und nach die Werte 2, 3, 4 usw. bis 10 ein, und schließlich auch 11. Bei diesem Wert ist die Durchlaufbedingung »kleiner oder gleich 10« jedoch nicht mehr erfüllt und die Schleife wird nicht mehr weiter durchlaufen.
Am Ende erhält die Variable html im Beispiel noch den HTML-Code zum Schließen der noch offenen Elemente. Damit ist der gesamte Code der Tabelle in der Variablen gespeichert und wird mit document.write() ausgegeben.

for-Schleifen können selbstverständlich auch verschachtelt sein. Das wäre im Beispiel nötig, wollte man mehrere Tabellenzeilen erzeugen. Die äußere for-Schleife würde dann so viele Zeilen erzeugen wie nötig und die innere pro Zeile die gewünschte Anzahl Zellen.
Eine Variante der for-Schleife ist die for-in-Schleife. Diese Variante eignet sich besonders gut zum Traversieren von Arrays.

Ein Beispiel:

var names = new Array("Anna", "Berta", "Cäsar", "Dora", "Emil");
for(name in names)
document.write(names[name] + "<br>");

Das Beispiel deklariert einen Array names, bestehend aus fünf Zeichenkettenwerten. Mithilfe der for-in-Schleife werden die Namen untereinander ins Browser-Fenster geschrieben. Dazu wird eine Traversionsvariable verwendet – im Beispiel heißt sie name. Der Ausdruck name in names bedeutet dann so viel wie »der Reihe nach alle Elemente aus dem Array names, wobei in name jeweils das aktuelle Element gespeichert ist«.

Auf die Syntax und Möglichkeiten von Arrays gehen wir in Abschnitt 7.3.11 näher ein.

while-Schleifen und do-while-Schleifen
Schleifen mit while und do-while eignen sich für Fälle, in denen nicht bekannt oder errechenbar ist, wie oft die Schleife durchlaufen werden soll. Im Schleifenkopf, der bei der while-Schleife oberhalb des Schleifeninhalts und bei der do-while-Schleife unterhalb des Schleifeninhalts notiert wird, wird lediglich eine Durchlaufbedingung formuliert. Dafür, dass diese Bedingung irgendwann nicht mehr erfüllt ist und die Schleife abgebrochen wird, muss der Schleifeninhalt sorgen. Funktioniert das nicht, so entsteht eine so genannte Endlosschleife.

Beginnen wir mit einem solchen Beispiel, um die Problematik zu verdeutlichen:

var x = 1;
while(x == 1)
document.write(x + " ");

Mit so wenig JavaScript-Code können Sie jeden Browser ärgern. Im günstigsten Fall reagiert er nach wenigen Sekunden mit einem Dialogfenster, welches nachfragt, ob das Script abgebrochen werden soll. Es kann aber auch sein, dass die gesamte Browser-Anwendung nicht mehr reagiert und abstürzt.
Deklariert wird eine Variable x mit dem Initialwert 1. Dann wird als Durchlaufbedingung für eine while-Schleife geprüft, ob x den Wert 1 hat. Das ist der Fall, also wird die abhängige document.write()-Anweisung ausgeführt. Der Wert von x wird aber nirgends geändert. Daher bleibt die Schleifendurchlaufbedingung immer erfüllt und die Schleife bricht nie ab.

Ein ordentlicheres Beispiel für eine while-Schleife ist dieses:

x = 1;
while(x != 5) {
x = parseInt(Math.random() * 10);
document.write(x + " ");
}

In diesem Beispiel wird ebenfalls x mit 1 initialisiert. Die Durchlaufbedingung ist, dass x nicht den Wert 5 hat. Da x zunächst 1 ist, ist die Bedingung also erfüllt und die Programmausführung gerät in die Schleife. Innerhalb der Schleife wird jedoch der Wert für x neu ermittelt. Allerdings ist das Ergebnis nicht bekannt. Denn es handelt sich um eine Zufallszahl zwischen 0 und 9 (auf die Methode Math.random() gehen wir später noch ein). Anschließend wird der Wert von x ins Browser-Fenster geschrieben. Da x in jedem Schleifendurchgang einen neuen zufälligen Wert zwischen 0 und 9 erhält, ist einigermaßen sicher, dass nach einer Weile auch mal der Wert 5 vorkommt. Dann ist die Durchlaufbedingung nicht mehr erfüllt und die Schleife bricht ab.

Bei do-while-Schleifen wird zuerst der Schleifeninhalt ausgeführt und erst anschließend wird die Durchlaufbedingung geprüft. Dadurch ist sichergestellt, dass die Schleife mindestens einmal durchlaufen wird. In manchen Fällen kann dies wichtig sein.

Ein Beispiel:

var x = 1;
do {
document.write("ein Satz mit x<br>");
x += 1;
} while(x % 2 == 1)

Im Beispiel wird x mit 1 initialisiert. Anschließend tritt die Programmausführung in den Schleifeninhalt ein, markiert durch do. Die Anweisungen innerhalb des Schleifenkörpers sind als Block in geschweifte Klammern gesetzt, da es mehr als eine Anweisung ist. Die Schleifendurchlaufbedingung wird am Ende nach der schließenden geschweiften Klammer formuliert. Die Syntax ist dabei die gleiche wie bei while-Schleifen. Im Beispiel lautet die Schleifendurchlaufbedingung »wenn x geteilt durch 2 einen Rest von 1 ergibt«. Da x innerhalb des ersten Schleifendurchlaufs durch x += 1 auf 2 erhöht wird, ist die Bedingung, wenn sie zum ersten Mal geprüft wird, bereits nicht erfüllt. Die Schleife bricht also nach dem einen Durchlauf ab.

Schleifenkontrolle
In manchen Fällen kann es erforderlich sein, zusätzlich zur Schleifendurchlaufbedingung innerhalb des Schleifeninhalts Abbruchbedingungen zu formulieren oder auch den nächsten Schleifendurchlauf zu erzwingen, bevor der gesamte Schleifeninhalt abgearbeitet wurde. Für solche Zwecke stehen die Statements break und continue zur Verfügung: break bricht eine Schleifenabarbeitung sofort ab, continue erzwingt an der Stelle, wo es notiert ist, den nächsten Schleifendurchlauf. Beide Statements hängen typischerweise von einer if-Abfrage ab.

Dazu folgendes Beispiel:

x = 1;
while(x != 5) {
x = parseInt(Math.random() * 10);
if(x == 0)
break;
y = 10 / x;
document.write(y + "<br>");
}

Das Beispiel erweitert jenes zu while-Schleifen. In diesem Fall ist jedoch zusätzlich zur Schleifendurchlaufbedingung x != 5 noch eine Bedingung x == 0 formuliert, bei der, falls sie erfüllt ist, die Schleifenverarbeitung abgebrochen wird. Grund ist in unserem Beispielfall zu verhindern, dass anschließend eine Division durch 0 durchgeführt wird, was zu einem ungültigen Ergebnis führen würde. Das Statement break wird wie eine Anweisung notiert und mit Semikolon abgeschlossen. Das Gleiche gilt für continue.

3.6 Funktionen, Parameter und Return-Werte

Funktionen haben wir in einigen Beispielen bereits kennen gelernt. Das erste Charakteristische daran ist: Anweisungen, die in Funktionen stehen, werden nicht gleich beim Einlesen des Scripts ausgeführt, sondern erst dann, wenn die Funktion aufgerufen wird. Der enthaltene Code ist wiederverwendbar und kann so oft ausgeführt werden, wie die Funktion aufgerufen wird.

Dieses Merkmal teilen Funktionen mit der klassischen Unterprogrammtechnik. Funktionen haben aber noch weitere Vorteile: Sie können Werte übergeben bekommen (Parameter), diese verarbeiten und Werte an die aufrufende Anweisung zurückgeben (Return- Werte oder Rückgabewerte).

Die Arbeitsweise von Funktionen soll an einem Komplettbeispiel verdeutlicht werden. Das Beispiel stellt eine eigene Suche-Ersetze-Funktion für Zeichenketten vor, die es in dieser Form in JavaScript nicht gibt, die aber praktische Dienste leisten kann. Die Funktion erwartet einen Input, den sie aus Formulareingaben des Anwenders erhält, und liefert einen Output, der dynamisch ins Anzeigefenster geschrieben wird. Das HTML-Dokument mit der Beispielfunktion hat folgenden Quelltext:

Listing 7.6: HTML-Dokument mit eigener Suche-Ersetze-Funktion

Bilder


Bilder

Abbildung 7.7: Formular zum Testen der Suche-Ersetze-Funktion

Im Formular der Seite kann der Anwender einen Text eingeben, eine Zeichenkette, nach der im Text gesucht werden soll, und eine Zeichenkette, durch die sie ersetzt werden soll. Beim Klick auf den Button Ergebnis wird der Text unterhalb des Formulars ausgegeben, und zwar so, dass darin eventuell gefundene Stellen ersetzt sind. Dazu wird mit onClick= die Funktion string_replace() aufgerufen, die in einem script-Bereich im Dateikopf notiert ist.

Funktionen beginnen mit dem Schlüsselwort function. Dahinter folgt der frei wählbare Name der Funktion. Unmittelbar hinter dem Namen werden ein Paar runde Klammern () notiert. Innerhalb der Klammern können Parameternamen notiert werden. Die Parameternamen können Sie wie Variablennamen frei bestimmen.
Funktions- und Parameternamen müssen den üblichen Konventionen genügen. Es sind also nur Buchstaben A bis Z, a bis z, Ziffern 0 bis 9 und der Unterstrich erlaubt. Das erste Zeichen darf keine Ziffer sein.

Der gesamte Funktionsinhalt ist ein Block und wird in geschweifte Klammern { und } eingeschlossen. Innerhalb des Funktionsblocks kann auf die übergebenen Parameter wie auf Variablen zugegriffen werden. Die Parameter enthalten Werte, die der Funktion beim Aufruf übergeben werden müssen. In unserem Beispiel erwartet die Funktion string_replace() drei Parameter: string, search und replace. Beim Aufruf der Funktion werden die drei erwarteten Parameter übergeben. Es handelt sich um die mittels DOM-Zugriffssyntax ermittelten Werte aus den Formularfeldern mit den id-Namen text, search_for und replace_by. In den drei Parametern stehen also, wenn die Funktion sie übergeben bekommt, die vom Anwender in den entsprechenden Feldern eingegebenen Werte.

Die Funktion selbst deklariert eine Variable namens new_string. Die Arbeit der Funktion besteht darin, den Wert des Parameters string Zeichen für Zeichen abzuarbeiten, eventuelle Ersetzungen vorzunehmen und die Variable new_string nach und nach mit der Kopie von string inklusive eventueller Ersetzungen zu füllen.
Am Ende wird new_string mit return zurückgegeben. Die Fähigkeit, solche Return-Werte an die funktionsaufrufende Anweisung zurückzugeben, ist eine besonders wertvolle Einrichtung. Gerade in Verbindung mit Parametern wird eine Funktion somit zu einer eigenen kleinen Datenverarbeitungsmaschine, die einen Input erhält und einen Output liefert. Die aufrufende Anweisung muss nur den Input übergeben und den Output empfangen.

Betrachten wir noch mal genau den Aufruf der Funktion string_replace() im HTMLCode des Buttons Ergebnis:

onClick="document.getElementById('result').innerHTML =
string_replace(document.getElementById('text').value,
document.getElementById('search_for').value,
document.getElementById('replace_by').value)

Die Zuweisung an onClick= besteht aus einer einzigen JavaScript-Anweisung. Dass diese etwas länger ist, liegt an den leider etwas langen DOM-Zugriffen, die darin notiert sind. Die Anweisung selbst besteht aus einer Zuweisung. Links des Zuweisungsoperators = muss der »Speicher« stehen, dem der Wert zugewiesen werden soll. Innerhalb von Java- Script ist dies häufig eine Variable. In unserem Fall ist es jedoch die Eigenschaft innerHTML des Elements mit dem id-Namen result. Das ist das p-Element, welches unten im HTMLDokument notiert ist. Die Funktion string_replace() schreibt ihren Return-Wert durch diese Zuweisung also direkt in das p-Element.

Funktionen müssen keine Parameter erwarten und keine Return-Werte liefern, aber sie können es. In Ihrem JavaScript-Code können Sie Funktionen einfach als Unterprogramme zur besseren Strukturierung benutzen oder als eigene kleine Programme, die aus einem Input einen Output erzeugen. In jedem Fall müssen Sie Code in Funktionen stecken, der nicht sofort beim Einlesen des Dokuments ausgeführt werden soll.

 


Das Tutorial ist ein Auszug aus dem Buch von Stefan Münz:

Professionelle Websites - Programmierung, Design und Administration von Webseiten
Addison-Wesley, 2. Auflage, 1136 Seiten, gebunden, komplett in Farbe, mit DVD

Die Veröffentlichung des Kapitels erfolgt mit freundlicher Genehmigung von
Pearson Education.

Mehr Informationen zu diesem wunderbaren Fachbuch für Webmaster und Webentwickler
gibt es hier: Professionelle Websites

Alle Teile des Buches: 

1 Intro
2 HTML und CSS
3 Dynamische Seiten mit JavaScript/DOM
4 Die Server-Seite
5 PHP und MySQL
6 XML
7 Betrieb von Websites
8 Referenz
Bilder
 

Kommentare
Achtung: Du kannst den Inhalt erst nach dem Login kommentieren.
Portrait von MaoMao
  • 09.01.2013 - 16:57

Gute Tutorial leicht erklärt.

Portrait von skyflight1981
  • 30.04.2008 - 01:00

Sehr nützlich und ausführlich!

x
×
×