vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 2

Tag 10

Anweisungen und Kontrollfluss- Steuerung

Auf dem heutigen Tagesprogramm stehen allgemein Anweisungen unter JavaScript und insbesondere solche, die zur Steuerung des Programmflusses gesetzt werden.

Anweisungen sind sprachspezifische Befehle bzw. Befehlsfolgen, welche zur Grundsyntax einer jeden Script- bzw. Programmiersprache zählen. Sie sind das Rückgrat aller programmtechnischen Entscheidungsstrukturen.

Allgemeine Anweisungen

Anweisungen werden in einem JavaScript der Reihe nach oder aufgrund einer bestimmten Konstellation ausgeführt. Dabei kann man verschiedene Arten von Anweisungen unterscheiden.

Blockanweisungen

In JavaScript werden größere Quellcodeabschnitte zu Blockstrukturen mit geschweiften Klammern

{ ... }

zusammengefasst, die dann einen Block bzw. eine Blockanweisung bilden. Dies haben wir in fast allen Beispielen bereits angewandt.

Deklarationsanweisungen

Deklarationsanweisungen sind die Einführung eines neuen Elements im Script. Etwa eine Variable oder eine Funktion. Es können aber auch andere Elemente eingeführt werden, wobei der Umfang der verschiedenen Elemente stark von der Programmier- oder Scriptsprache abhängt. Unter anderem gibt es die Deklaration von primitiven Datentypen, Datenfeldern, Methoden oder eines beliebigen Objekts. Zum Teil gibt es das auch in JavaScript - wir kommen noch darauf zurück.

Ausdrucksanweisungen

Ausdrucksanweisungen sind einmal das, was wir gestern intensiv behandelt haben - die Wertveränderung als Ergebnis der Verbindung von Operanden und Operatoren über die syntaktischen Regeln einer Scriptsprache. Dies ist die so genannte Zuweisungsanweisung, die rechts von einem Zuweisungsoperator einen Wert (konstant oder berechnet) stehen hat, der dem linken Ausdruck zugewiesen wird.

Alle Ausdrucksanweisungen müssen in JavaScript mit einem Semikolon beendet werden und werden immer vollständig durchgeführt, bevor die nächste Anweisung ausgeführt wird.

Die zweiten Varianten sind Auswahlanweisungen, die in einem Script in gewissen Situationen einen von mehreren möglichen Kontrollflüssen aussuchen. Sie dienen der Ablaufsteuerung von einem Script (wir gehen gleich genauer darauf ein).

Iterationsanweisungen

Iterationsanweisungen sind eine Angabe, unter welchen Voraussetzungen und wie oft nachfolgend notierte Anweisungen ausgeführt werden. Sie dienen also explizit der Ablaufsteuerung in einem Script. Im nachfolgenden Kapitel gehen wir auf diese wichtigen Kontrollfluss- Steuerungsmöglichkeiten ein.

Sprunganweisungen

Sprunganweisungen geben die Ablaufsteuerung eines Scripts an eine aufrufende Stelle zurück. Sie dienen der Ablaufsteuerung von Scripten. JavaScript kennt die Anweisung

return

zur Rückgabe eines Wertes und Rückgabe des Kontrollflusses sowie die Anweisung

break

In JavaScript 1.2 wurde eine Erweiterung von break vorgenommen, die aus vielen Programmiersprachen bereits bekannt ist: die break-Anweisung mit Angabe eines Labels, d.h. einer Sprungadresse die angibt, wo nach Ausführen der break-Anweisung mit der Abarbeitung des Codes fortgefahren werden soll. Das Label ist ein frei definierbarer Name an einer beliebigen Stelle im Quelltext, der mit einem nachgestellten Doppelpunkt notiert wird. Hinter dem Wort break können Sie dann durch Leerzeichen abgetrennt den Namen des Labels angeben. Diese Technik ist jedoch sehr kritisch zu betrachten, weil viele Browser sie nicht unterstützen. Schlimmer ist noch, dass sie die Erzeugung von so genanntem Spagetticode erlaubt, welcher in grauen Computerurzeiten über die unselige BASIC-Anweisung goto üblich war. Wir gehen nicht weiter darauf ein. Neben break und return gibt es in JavaScript noch die Anweisung

continue.

Sie können damit in einer Schleife unmittelbar den nächsten Schleifendurchlauf erzwingen und die nachfolgenden Anweisungen innerhalb der Schleife ignorieren.

Wir werden alle drei Sprunganweisungen gleich im Rahmen der Behandlung von Kontrollfluss-Anweisungen einsetzen und an Hand praktischer Beispiele erläutern.

Auswahl- und Iterationsanweisungen

JavaScript kennt die in den meisten Sprachen üblichen Auswahl- und Iterationsanweisungen. Zum Teil haben wir sie schon verwendet. Da gibt es beispielsweise die if-Auswahlanweisung.

if-Anweisung

Die if-Auswahlanweisung ist uns schon in einigen Beispielen begegnet. Wir wollen sie jetzt intensiver anschauen. Diese Kontrollstruktur ist das Analogon zu der wenn()-Funktion von Excel. Wenn eine Bedingung erfüllt ist, werden die nachfolgend notierten Anweisungen ausgeführt. Grundsätzliche Syntax ist immer die folgende:

if ([Bedingung])
{
...Anweisungen
}

Unter Bedingung versteht man eine Anweisung, die entweder wahr (true) oder falsch (false) sein kann. Zu deren Erstellung verwendet man in der Regel die Vergleichsoperatoren - gegebenenfalls in Verbindung mit logischen Operatoren. Wir haben dies schon mehrfach an den vorherigen Tagen angewandt. Ein Beispiel soll dennoch nicht fehlen. Eine andere sinnvolle Variante ist, wenn eine dort aufgerufene Funktion einen boolschen Rückgabewert liefert. Auch dazu führen wir ein Exempel durch.

Beispiel 1

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var pw = prompt("Bitte geben Sie Ihr Passwort ein","");
if(pw=="geheim")
{
document.write(
"<H1 align=center>Herzlich Willkommen auf meiner Homepage</H1>");
document.write("<br>");
}
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter PW1.html und laden Sie es in einen Browser. Beim Laden der Webseite werden Sie aufgefordert, ein Passwort einzugeben.

Abbildung 10.1:  Eingabe des Passwortes.

Wenn das Passwort geheim eingegeben wird, wird nachfolgend eine Webseite aufgebaut. Ansonsten passiert nichts weiter. Der Anwender sieht also nur eine leere Seite.

Abbildung 10.2:  Bei korrekter Eingabe des Passwortes wird die Seite aufgebaut

Wie wir gestern bei logischen Operatoren gesehen haben, kann eine Bedingung aus mehreren Bestandteilen bestehen. Das bedeutet, es muss entweder mehr als eine Bedingung notwendigerweise erfüllt sein oder es muss sich nur eine von mehreren Bedingungen bewahrheiten. In diesem Fall kommen die logischen Operatoren && für eine Und-Verknüpfung und || für eine Oder-Verknüpfung zum Einsatz. Diese können obendrein beide gleichzeitig verwendet werden, und auch die Anzahl der Bedingungen ist im Prinzip unbeschränkt. Es ist eigentlich nur ein logisches Problem, eine gewisse Anzahl von verknüpften Bedingungen auch so zu formulieren, dass sie den gewünschten Sinn repräsentieren.

Das Beispiel soll nun so umgeschrieben werden, dass die Bedingung in einer externen Funktion überprüft und deren Aufruf direkt in die if- Bedingung notiert wird.

Beispiel 2

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
function test(pass)
{
if(pw=="geheim") return true;
}
var pw = prompt("Bitte geben Sie Ihr Passwort ein","");
if(test(pw))
{
document.write(
"<H1 align=center>Herzlich Willkommen auf meiner Homepage</H1>");
document.write("<br>");
}
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter PW1b.html und laden Sie es in einen Browser. Das Script verhält sich vollkommen analog zu dem ersten Beispiel. Dennoch gibt es ein paar Stellen, die wir uns genauer anschauen wollen.

Da ist einmal die Zeile

if(test(pw)).

Diese Zeile beinhaltet die Situation, dass anstelle eines explizit dort notierten Vergleichs ein Funktionsaufruf steht. Diese dort angegebene Funktion sollte sinnvollerweise entweder true oder false zurückliefern, damit der nachfolgende Block entweder ausgeführt wird oder eben nicht.

Die Funktion test() selbst hat auch eine interessante Stelle:

if(pw=="geheim") return true;

Einmal sehen Sie die return-Sprunganweisung bei der Arbeit, aber es gibt noch etwas Interessantes. Was ist da neu gegenüber den bisherigen Fällen, wo wir die if-Anweisung verwendet haben?

Es fehlt der Block. Die Anwendung steht ohne Blockstruktur unmittelbar hinter der if-Anweisung. Das geht immer dann, wenn nur eine einzige Anweisung ausgeführt werden soll. Wir wollen dennoch in Zukunft von einem Block von Anweisungen reden.

Grundsätzlich ist eine if-Anweisung zur Behandlung einer Situation alleine oft nicht ausreichend. Meist wird eine Alternative notwendig sein. Für den Fall gibt es die Erweiterung else, die einen Block mit Anweisungen einleitet, welche immer dann (und nur dann) ausgeführt werden, wenn die vorangestellte Bedingung der if-Anweisung nicht erfüllt ist. Wenn bereits der if-Zweig ausgeführt wurde, wird der else-Zweig nicht ausgeführt. Grundsätzliche Syntax ist immer die folgende:

if ([Bedingung])
{
...Anweisungen
}
else
{
...alternative Anweisungen
}

Schreiben wir das Beispiel 1 nun so um, dass es zwei Alternativen gibt.

Beispiel 3

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var pw = prompt("Bitte geben Sie Ihr Passwort ein","");
if(pw=="geheim")
{
document.write(
"<H1 align=center>Herzlich Willkommen auf meiner Homepage</H1>");
document.write("<br>");
}
else
{
document.write(
"<H1 align=center>Leider nur für Mitglieder</H1>");
document.write("<br>");
}
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter PW2.html und laden Sie es in einen Browser. Beim Laden der Webseite werden Sie wie gehabt aufgefordert, ein Passwort einzugeben. Wenn das eingegebene Passwort wieder geheim lautet, wird die gleiche Webseite wie in Beispiel 1 aufgebaut. Ansonsten jedoch bekommt der Anwender in diesem dritten Beispiel eine Alternativseite angezeigt.

Abbildung 10.3:  Bei falscher Eingabe des Passwortes wird eine Alternativseite aufgebaut

Im else-Block können nun bei Bedarf auch weitere if-Anweisungen notiert werden. Das ist sehr oft der Fall, denn oft genügen zwei Alternativen nicht. Da in diesem Fall die if-Anweisung die einzige Anweisung des else-Blocks ist, kann das Schlüsselwort if direkt hinter else notiert werden (siehe unter Beispiel 2). Das sieht dann schematisch so aus:

if ([Bedingung 1])
{
...Anweisungen
}
else if ([Bedingung 2])
{
...alternative Anweisungen
}
else if ([Bedingung 3])
{
...alternative Anweisungen
}
.
.
.
else
{
...alternative Anweisungen
}

Die Anzahl der Blöcke ist beliebig und ob der abschließende else-Block vorhanden ist, ist nur eine Frage der Logik.

Beispiel 4:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var pw = prompt("Bitte geben Sie Ihre Spende ein","");
if(pw < 5000)
{
document.write("<H1 align=center>Geizhals</H1>");
document.write("<br>");
}
else if(pw < 10000)
{
document.write("<H1 align=center>Vielen Dank</H1>");
document.write("<br>");
}
else
{
document.write(
"<H1 align=center>Vielen, vielen Dank</H1>");
document.write("<br>");
}
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter Spende.html und laden Sie es in einen Browser. Beim Laden der Webseite werden Sie aufgefordert, einen Spendenbetrag einzugeben.

Abbildung 10.4:  Höhe der mildtätigen Gabe

Wenn der Betrag unter 5.000 ist, wird der if-Block ausgeführt, ist er unter 10.000, der else-if-Block und ansonsten der else-Block.

Abbildung 10.5:  So isses recht - else

Abbildung 10.6:  Na, ganz okay - else if

Abbildung 10.7:  Unzufriedenheit - if

Beachten Sie, dass die Struktur darauf aufbaut, dass das gesamte Konstrukt abgebrochen wird, wenn einer der Blöcke ausgeführt wurde. Das soll bedeuten, dass eine Eingabe unter 5.000 den if-Block ausführt, dann aber nicht mehr die anderen beiden Blöcke, obwohl die Eingabe auch die Bedingung kleiner 10.000 erfüllt hätte. Der erste Treffer bei kleiner 5.000 verhindert die Abprüfung weiterer Möglichkeiten.

Der Konditional-Operator als Kurzschreibweise für die if-else-Anweisung

Erinnern Sie sich an den konditionalen Operator von gestern? Es ist eine Kombination aus dem Fragezeichen und Doppelpunkt und eine Kurzschreibweise für ein if-else-Konstrukt. Vor dem Fragezeichen muss in Klammern eine Bedingung formuliert werden. Hinter dem Fragezeichen werden die Anweisungen notiert, die ausgeführt werden, wenn die Bedingung wahr ist. Hinter dem nachfolgenden Doppelpunkt folgen die Anweisungen, die sonst im else-Block stehen.

Beispiel 5:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var pw = prompt("Bitte geben Sie Ihre Spende ein","");
pw < 5000 ? alert("Geizhals") : alert("Vielen Dank");
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter Konditional.html und laden Sie es in einen Browser. Beim Laden der Webseite werden Sie aufgefordert, einen Spendenbetrag einzugeben, und erhalten die entsprechende Reaktion.

Wegen der schlechten Lesbarkeit sollten Sie - zumindest in der Anfangsphase - von diesem Konstrukt Abstand nehmen.

Die switch-Fallunterscheidung

Wenn man im Ablauf eines Scripts mehr als zwei Wahlmöglichkeiten unterscheiden muss, bietet sich in einigen Situationen eine aufeinander folgende Notation von if-else-Anweisungen an. Dies kann aber bei einer größeren Anzahl von Fallunterscheidungen recht unübersichtlich und mühsam werden. Es gibt aber in JavaScript alternative Techniken, die in bestimmten Fällen eine sinnvolle Lösung erlauben.

Seit der JavaScript-Version 1.2 gibt es eine mögliche Fallunterscheidung über ein Konstrukt, welches in vielen anderen Programmiersprachen schon lange zum Standard gehört - die Fallunterscheidung über switch-case.

Wesentlicher Vorteil gegenüber der if-else-Struktur ist, dass Sie auf einfache und elegante Weise mehr als zwei Fälle unterscheiden können. Die Syntax einer switch-Fallunterscheidung sieht im Allgemeinen folgendermaßen aus:

switch([auswahl])
{
case [Fall 1]:
...
break;
case [Fall 2]:
...
break;
.
.
.
default:
...
break;
}

Mit dem Schlüsselwort switch leiten Sie die Fallunterscheidung ein. Als Argument wird, in runden Klammern eingeschlossen, eine Variable oder ein Ausdruck angegeben, für dessen aktuellen Wert Sie die Fallunterscheidung durchführen. Dies kann ein beliebiger Datentyp sein, der unter JavaScript erlaubt ist (etwa eine Zahl, aber auch ein Text). Er wird auf Übereinstimmung mit einem der nachfolgend hinter dem Schlüsselwort case notierten Werte geprüft.

Die einzelnen Fälle, zwischen denen unterschieden werden soll, werden untereinander aufgelistet und innerhalb geschweifter Klammern als Blöcke hinter case notiert.

So elegant die switch-Fallunterscheidung auch ist - sie ist bei weitem nicht so flexibel wie die if-else-Struktur. Man kann nur auf feste Werte abprüfen und beispielsweise nicht direkt mit Größer- oder Kleiner-Vergleichen arbeiten. Dafür zeigt aber die switch-Fallunterscheidung nach einem Treffer eine interessante Verhaltensweise, die wir gleich kennen lernen.

Beispiel 6:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var ergebnis=prompt(
"Bitte geben Sie eine Zahl zwischen 1 und 10 ein","");
switch(ergebnis)
{
case 1:
document.write("Fall 1 wird genommen");
document.write("<P>");
break;
case 2:
document.write("Fall 2 wird genommen");
document.write("<P>");
break;
case 3:
document.write("Fall 3 wird genommen");
document.write("<P>");
break;
case 4:
document.write("Fall 4 wird genommen");
document.write("<P>");
break;
default:
document.write("Keiner der Fälle wird genommen");
document.write("<P>");
break;
}
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter SwitchTest1.html und laden Sie es bitte zuerst in den Netscape Navigator. Beim Laden der Webseite werden Sie aufgefordert, eine Zahl zwischen 1 und 10 einzugeben. Dieser Wert wird in einer Variablen gespeichert. In dem switch-Block wird der Fall ausgewählt, dessen Prüfwert mit diesem Wert übereinstimmt. Die Anweisung break unterbricht die weitere Abarbeitung dieser switch-Fallunterscheidung und springt hinter den gesamten switch-Block. Wenn keine der Auswahlmöglichkeiten auf den Wert der überprüften Variablen zutrifft, wird der mit default bezeichnete Fall ausgewählt.

Abbildung 10.8:  Default-Fall

Abbildung 10.9:  Eingabe war 4 - je nach Wert wird ein Zweig ausgewählt

Abbildung 10.10:  Eingabe des Werts

Laden Sie nun die Datei in den Internet Explorer. Es wird immer der Default-Fall genommen. Unabhängig von der Eingabe. Was könnte der Grund sein?

Das Problem basiert einmal auf dem lockeren Umgang von JavaScript mit Datentypen und außerdem darauf, dass der Internet Explorer kein JavaScript kann. Erinnern Sie sich? Er muss JavaScript erst in JScript übersetzen und kann erst dann das Script ausführen. Hier haben wir einen der Fälle, wo es dabei Probleme gibt. Der Navigator konvertiert die Benutzereingabe beim Abprüfen in der switch-Anweisung in Zahlen, der Internet Explorer bleibt bei Strings und findet deshalb keine Übereinstimmung.

Welche Lösungen gibt es für das Dilemma. Einmal ist es grundsätzlich möglich, in der switch-Anweisung auch auf Übereinstimmung mit Zeichenketten zu überprüfen (auch mehr als ein Buchstabe). Wenn Sie jeden Wert hinter der jeweiligen case-Anweisung in Hochkommata setzen (etwa so: case "3":), wird auch der Internet Explorer zurechtkommen. Der Netscape Navigator kommt ebenfalls damit zurecht, weshalb Sie für den Fall von zu testenden Benutzereingaben damit auf der sicheren Seite sind. Aber auch die Übersetzung von Benutzereingaben in nummerische Werte und dann den unveränderten Test kann man für den Internet Explorer hinbiegen, ohne dass dann der Netscape Navigator Probleme bekommt. Sie wissen schon wie. Oder erinnern Sie sich nicht mehr an den Trick, Typkonvertierungen eines Strings mit nur Zahlen darin durch Multiplikation mit 1 auszulösen (Tag 8, Beispiel 6)? Die Zeile mit der Entgegennahme der Benutzereingabe könnte beispielsweise so verändert werden:

var ergebnis = 1 * prompt(
"Bitte geben Sie eine Zahl zwischen 1 und 10 ein","");

Die switch-Anweisung hat nun noch einige Feinheiten zu bieten, die wir behandeln sollten. Da ist einmal die Anordnung der case-Blöcke. Diese Anordnung muss nicht in einer bestimmten Reihenfolge erfolgen. Das ist deshalb klar, weil nur auf exakte Übereinstimmung geprüft wird. Es ist aber auch möglich, dass ein Wert in mehreren case-Blöcken überprüft wird. Das ist aber meist unsinnig, weil der erste Treffer genommen wird und nachfolgende identische case-Prüfungen irrelevant werden.

Eine andere Feinheit ist aber nicht so trivial. Haben Sie sich schon gefragt, warum am Ende jedes Blocks das Schlüsselwort break (eine Sprunganweisung) steht? Damit stellen Sie sicher, dass nach einem Treffer die nachfolgenden Fälle nicht ebenso ausgeführt werden, was in der Regel nicht gewünscht ist. Wie das zu verstehen ist, wird ein Beispiel demonstrieren. Dabei unterbleibt einfach einmal die Notation von break.

Beispiel 7:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var pw = prompt("Bitte geben Sie Ihre UserId ein","");
switch(pw)
{
case "Gast":
document.write("Willkommen als " + pw);
document.write("<P>");
document.write("Sie sehen hier ein eingeschränktes Angebot");
//break;
case "Bob":
document.write("Willkommen " + pw);
document.write("<P>");
document.write("Hier ist Ihr Angebot");
//break;
case "Admin":
document.write("Willkommen " + pw);
document.write("<P>");
document.write("Hier ist die Konfigurationsseite");
//break;
default:
document.write("<H1>Nur für Mitglieder</H1>");
document.write("<P>");
}
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter switchTest2_ohneBreak.htm und laden Sie es in einen Browser. Beim Laden der Webseite werden Sie aufgefordert, eine UserId einzugeben. Dieser Wert wird in einer Variablen gespeichert. In dem switch-Block wird der Fall ausgewählt, dessen Prüfwert mit diesem Wert übereinstimmt. Geben Sie beispielsweise als UserId Gast ein. Wahrscheinlich erwarten Sie, nur die Seite für den Gast zu sehen.

Abbildung 10.11:  Das wird aber angezeigt

Abbildung 10.12:  Das wird wahrscheinlich erwartet

In der Tat werden aber alle Blöcke nach dem ersten Treffer abgearbeitet.

Nochmals zur Sicherheit - diese Anweisung steht erst in JavaScript 1.2 zur Verfügung. Browser, die diese Anweisung nicht verstehen, werden mit einer Fehlermeldung reagieren. Dazu zählt auch der Opera 3.6. Trotz der eleganteren Lösung über switch ist es sicherer, mehrere if-Abfragen hintereinander zu schalten.

while und do-while

Zwei eng verwandte und sehr oft eingesetzte Kontrollfluss-Anweisungen sind die while- und die do-while-Schleife. Beide führen eine Prüfung einer Bedingung durch und wiederholen die im inneren Block notierten Anweisungen so lange, bis die Bedingung nicht mehr erfüllt ist. Die allgemeine Syntax ist folgende:

while ([Bedingung])
{
...Anweisungen
}

bzw.

do 
{
...Anweisungen
}
while ([Bedingung])

Die Bedingung können wie bei der if-Anweisung über Rückgabewerte von Funktionen oder direkte Vergleiche überprüft werden.

Wie unterscheiden sich nun while- und do-while-Schleifen? Bei der while- Schleife gilt, dass, wenn eine Bedingung bei Erreichen der Schleife falsch ist, die Anweisungen im Block überhaupt nicht durchgeführt werden.

Die do-while-Schleife ist eine Abart der normalen while-Schleife und steht erst seit der Java-Version 1.2 zur Verfügung. Der wichtigste Unterschied zu der normalen while-Schleife ist, dass bei der do-while-Schleife die im Inneren notierten Anweisungen auf jeden Fall einmal ausgeführt werden, bevor die Schleifenbedingung überprüft wird.

Eine kleine Eselsbrücke ist, dass bei der while-Schleife die Überprüfung im Quelltext vor dem Block mit den Anweisungen steht, bei der do-while-Schleife hinter dem Block mit den Anweisungen.

Beide Schleifen benötigen in ihrem Inneren immer eine Anweisung, die eine Situation schafft, mit der die Schleife abgebrochen werden kann. Andernfalls erzeugen Sie unter Umständen eine Endlosschleife.

Unter einer Endlosschleife versteht man eine Wiederholung von Anweisungen im Inneren, wo niemals eine Situation eintritt, die für eine Beendigung der Wiederholung sorgt. Dies kann man sinnvoll nutzen - etwa ein Werbefenster, wo eine Folge von Grafiken immer wieder abgespielt werden soll. Oder eine Hintergrundmusik. Es kann aber auch als Fehler passieren. In diesem Fall bleibt oft nur die Beendigung eines Programms oder gar ein Neustart des Rechners.

Normalerweise erfolgt die Generierung einer Abbruchsituation darüber, dass die in der Bedingung geprüfte Variable im Inneren so verändert wird, dass irgendwann die Bedingung nicht mehr erfüllt ist. Es kann aber auch im Inneren mit einer zusätzlichen Anweisung (etwa der if-Anweisung) eine Unterbrechung ausgelöst werden - etwa mit einem break oder return. Wir testen dies in mehreren Beispielen.

Beispiel 8:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var zahl=prompt(
"Geben Sie eine Zahl grösser 0 ein","");
var zaehler=0;
while(zaehler <= zahl)
{
document.write(zaehler + " ");
zaehler++;
}
document.write("<br>");
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter while1.html und laden Sie es in einen Browser. Beim Laden der Webseite werden Sie aufgefordert, eine Zahl größer 0 einzugeben. Dieser Wert wird in einer Variablen gespeichert. Daneben gibt es eine Zählvariable, die zuerst auf 0 gesetzt ist. Die Bedingung in der nachfolgenden while-Überprüfung ist wahr und die Anweisungen werden ausgeführt. Nach der Ausgabe des Wertes und einem Leerzeichen wird der Wert der Variablen um 1 erhöht. Wir haben hier eine Anwendung von dem Inkrement-Operator, der dem Ausdruck zaehler = zaehler + 1; entspricht. Das Durchlaufen der Schleife wird so lange fortgesetzt, bis die Variable den Wert erreicht, den der Anwender eingegeben hat. Dann ist die Bedingung in der while-Überprüfung falsch und die Anweisungen werden nicht mehr ausgeführt.

Abbildung 10.13:  Die Anzeige bei Eingabe 42

Das nächste Beispiel zählt nicht bei jedem Durchlauf eine Zählvariable mit, sondern ruft eine andere Funktion auf, die in einer if-Anweisung die Übereinstimmung mit einem gewissen Wert prüft. Je nach Übereinstimmung wird mit return ein Rückgabewert geliefert, der dann die aufrufende Schleife abbricht oder nicht.

Beispiel 9:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var test=true;
function pruefePW(pw)
{
if(pw=="geheim") return false;
alert("Passwort leider nicht richtig");
return true;
}
function lade()
{
while(test)
{
test=pruefePW(prompt("Geben Sie das Passwort ein",""));
}
document.write("<H1>Willkommen</H1>");
}
</SCRIPT>
</HEAD>
<BODY onLoad="lade()">
</BODY>
</HTML>

Speichern Sie das Script unter while2.html und laden Sie es in einen Browser. Die while-Schleife überprüft eine Boolean-Variable, ob sie den Wert true hat. Die Zeile

while(test)

ist eine oft zu findende Kurzschreibweise für dies:

while(test==true)

Im Inneren der Schleife wird diese Variable nicht direkt verändert, sondern das vom Anwender eingegebene Passwort an eine Funktion als Übergabewert übergeben und dort ein boolscher Rückgabewert generiert, welcher der Testvariablen zugewiesen wird. Nur wenn Sie das Passwort geheim eingeben, wird die Webseite aufgebaut. Bei jeder anderen Eingabe erscheint die Meldung, dass das Passwort nicht stimmt. Es ist auch nicht möglich, die Schleife über den Abbrechen-Button des prompt()-Fensters zu beenden. Dieser beendet ja nur das Fenster, aber die Situation zum Abbrechen der Schleife ist nicht gegeben.

Wenn Sie logische Fehler in den Abbruchbedingungen der Schleife haben und diese nie erfüllt sind, erzeugen Sie eine Endlosschleife. In Verbindung mit Mitteilungs- oder Dialogfenstern kann das fatal sein. Der Browser lässt sich nicht mehr schließen. Sie müssen entweder den Task-Manager einsetzen oder gar den Rechner neu starten.

Eine weitere sinnvolle Möglichkeit, eine while-Schleife abzubrechen, ist der Einsatz von break.

Beispiel 10:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var pw;
function lade()
{
while(true)
{
pw=prompt("Geben Sie das Passwort ein","");
if(pw=="geheim") break;
}
document.write("<H1>Willkommen</H1>");
}
</SCRIPT>
</HEAD>
<BODY onLoad="lade()">
</BODY>
</HTML>

Speichern Sie das Script unter while3.html und laden Sie es in einen Browser. Die while-Schleife überprüft bei diesem Beispiel überhaupt keine Variable oder sonst irgendetwas. Die Bedingung hat immer den Wert true, denn dieser ist als Konstante dort eingegeben. Syntaktisch ist das vollkommen okay und ein beliebter Trick, wenn man Endlos-Schleifen bewusst programmieren möchte (beispielsweise für eine Diashow, die sich endlos wiederholt). Für unseren Fall wollen wir jedoch die Schleife auch irgendwann abbrechen. Da keine Variable überprüft wird, macht ein Setzen von Variablen im Inneren der Schleife auch keinerlei Sinn. Die Zeile

if(pw=="geheim") break;

überprüft die Anwendereingabe und ruft bei Übereinstimmung die Sprung- Anweisung break auf. Diese bricht unmittelbar die umgebende Schleife ab.

Testen wir nun noch die Besonderheit der do-while-Schleife.

Beispiel 11:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var test=100;
function lade()
{
do
{
document.write("<H1>Willkommen</H1>");
test++;
}
while(test<1)
}
</SCRIPT>
</HEAD>
<BODY onLoad="lade()">
</BODY>
</HTML>

Speichern Sie das Script unter dowhile.htm und laden Sie es in einen Browser. Die Schleife wird einmal durchlaufen, obwohl die auf 100 gesetzte Testvariable sicher nicht der Bedingung, kleiner als 1 zu sein, genügt.

Die for-Schleife

Die letzte Programmfluss-Kontrollanweisung ist die for-Schleife. In dieser Kontrollstruktur wird eine vorgegebene Anzahl von Durchgängen festgelegt. So oft wie angegeben, werden die Anweisungen im Inneren der Schleife ausgeführt. Bei jedem Durchlauf wird die Zählvariable um eine Einheit (deren Größe in der Schleife als Letztes angegeben wird) hochgezählt. Grundsätzliche Syntax:

for ([Zählvar];[Bedingung];[Schrittweite der Zählvar])
{
...Anweisungen
}

Die Schleifenform eignet sich hervorragend zur Initialisierung von Arrays (darauf kommen wir noch) oder zur Beeinflussung von Situationen, wo gleichartige Dinge eine vorgegebene Anzahl-mal ablaufen.

Diese Struktur ist ein wichtiger Fall, in dem oft mit so genannten schleifenlokalen Variablen gearbeitet wird. Das bedeutet, die Zählvariable wird über die for-Anweisung deklariert und ist dann auch nur dort vorhanden.

Beispiel 12:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var zaehler;
var eingabe;
eingabe=prompt("Geben Sie bitte eine Zahl zwischen 10 und 50 ein","");
for(zaehler=0;zaehler<=eingabe;zaehler++)
{
document.write(zaehler + " ");
}
document.write("<P>");
for(zaehler=10;zaehler<=eingabe;zaehler=zaehler + 2)
{
document.write(zaehler + " ");
}
document.write("<P>");
for(zaehler=100;zaehler>=eingabe-100;zaehler=zaehler -7)
{
document.write(zaehler + " ");
}
document.write("<P>");
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter for1.htm und laden Sie es in einen Browser. Mit dem Wert, den der Anwender eingibt, wird der Endwert des jeweiligen Schleifendurchlaufs ermittelt. Dies kann auch über irgendwelche Berechnungen erfolgen.

Abbildung 10.14:  Die Anzeige bei Eingabe 42

Die Zeile

for(zaehler=0;zaehler<=eingabe;zaehler++)

zählt von einem Startwert 0 jeweils in Einerschritten bis zu dem Endwert, den der Anwender eingegeben hat. Dabei wird für die Intervallgröße der Inkrement-Operator eingesetzt.

Die Zeile

for(zaehler=10;zaehler<=eingabe;zaehler=zaehler + 2)

zählt von einem Startwert 10 jeweils in Zweierschritten bis zu dem Endwert, den der Anwender eingegeben hat. Das sind also weniger Durchläufe als bei der ersten Schleife.

Die Zeile

for(zaehler=100;zaehler>=eingabe-100;zaehler=zaehler-7)

zählt von einem Startwert 100 rückwärts jeweils in Siebenerschritten bis zu dem Endwert, den der Anwender eingegeben hat, minus 100. Die Überprüfung der Bedingung muss hier auf »Kleiner« bzw. »Kleinergleich« erfolgen.

Ein Spezialfall der for-Schleife ist die for...in-Schleife. Wir werden diese im Zusammenhang mit Arrays an Tag 15 kennen lernen.

Kombinierte Anwendungen von Kontrollfluss- Anweisungen

In vielen etwas anspruchsvolleren Situationen muss man Kontrollfluss- Anweisungen kombinieren. Das kann über Verbinden von Bedingungen mit logischen Operatoren erfolgen, aber auch über die Kombination von mehreren Kontrollfluss-Anweisungen. Das haben wir etwa im Beispiel 10 gesehen - innerhalb einer while-Schleife wird da eine if-Abfrage eingebaut. Spielen wir noch ein Beispiel dieser Art durch, wo eine for- Schleife im Inneren eine if-Abfrage eingebaut hat.

Beispiel 13:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
var zaehler;
for(zaehler=0;zaehler<=100;zaehler++)
{
if((zaehler*2)%2!=(zaehler%2)*2) continue;
document.write(zaehler + " ");
}
document.write("<P>");
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter for2.htm und laden Sie es in einen Browser. Das Beispiel zeigt einen kleinen Trick, wie man gerade und ungerade Zahlen trennen kann. Die Anweisung

(zaehler*2)%2

ist für alle Zahlen 0. Dahingegen ist die Anweisung

(zaehler%2)*2

nur für gerade Zahlen 0, für ungerade 2. Die Zeile

if((zaehler*2)%2!=(zaehler%2)*2) continue;

vergleicht, ob die beiden Werte ungleich sind. Falls ja, wird die Anweisung continue ausgelöst, die Sie hier nun auch in der Praxis sehen. Unmittelbar wird ein neuer Schleifendurchlauf ausgelöst, und die Ausgabe jedes ungeraden Wertes unterbleibt.

Abbildung 10.15:  Nur gerade Zahlen werden ausgegeben

Auch das Verschachteln von Kontrollfluss-Anweisungen gleichen Typs findet man oft. Beispielsweise verschachtelte for-Schleifen, wie im nächsten Beispiel:

Beispiel 14:

Geben Sie folgenden Quelltext ein:

<HTML>
<HEAD>
<SCRIPT language="JavaScript">
for(zaehler=0;zaehler<=10;zaehler++)
{
for(i=0;i<3;i++)
document.write(zaehler + " ");
document.write("<BR>");
}
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

Speichern Sie das Script unter for3.htm und laden Sie es in einen Browser.

Abbildung 10.16:  Die Wirkung von verschachtelten for-Schleifen

Bei jedem Durchlauf der äußeren for-Schleife wird die innere Schleife dreimal ausgeführt.

Zusammenfassung

Am heutigen Tag standen Anweisungen auf dem Programm. Insbesondere Kontrollfluss-Anweisungen, oft in Verbindung mit Sprung-Anweisungen bilden das Rückgrad von Scripten, die auf unterschiedliche Situationen dynamisch reagieren können. JavaScript kennt folgende Anweisungen zur Kontrollfluss-Steuerung:

Fragen und Antworten

Frage:
Warum muss die break-Anweisung in einer switch-case-Anweisung verwendet werden, wenn die Blöcke nach dem Treffer nicht abgearbeitet werden sollen? Man könnte die Anweisung in der Konzeption von JavaScript doch auch so bauen, dass dies automatisch erfolgt.

Antwort:
Das stimmt natürlich, aber so, wie es konzipiert ist, kann man es auch sinnvoll einsetzen. Bei einer entsprechenden Anordnung der case-Blöcke kann man beispielsweise ab einem gewissen Treffer alle nachfolgende Schritte ausführen lassen. Etwa um Dinge mitzuzählen.

Frage:
Unterscheiden sich Anweisungen in JavaScript stark von Anweisungen in anderen Sprachen?

Antwort:
Nein. Es gibt nur wenige Details, wo sich Programmier- und Scriptsprachen in diesem Bereich unterscheiden. Eine Anweisung, wo es zwischen verschiedenen Sprachen Unterschiede gibt, ist die switch-case-Anweisung.

Frage:
Können bei verschachtelten for-Schleifen gleiche Namen für die Zählvariablen in den ineinander verschachtelten Schleifen verwendet werden?

Antwort:
Nein. Sie müssen sich unterscheiden.

Workshop

Experimentieren Sie mit den in diesem Kapitel durchgesprochenen Beispielen. Insbesondere die Verschachtelung von Anweisungen ist nicht ganz trivial und sollte ausführlich geübt werden.

Kontrollfragen

Im Anhang »Antworten zu den Kontrollfragen« finden Sie die Antworten zu den jeweils am Ende einer Lektion notierten Fragen.

  1. Stimmt die Syntax?
    for(zaehler==0;zaehler<=10;zaehler++)
  2. Gibt es die Sprunganweisung Return?
  3. Stimmt die Syntax?
    for(zaehler=0;zaehler<=10;zaehler)
  4. Stimmt die Syntax?
    if(i<10)
  5. Was ist der Unterschied zwischen break und continue?
  6. Stimmt die Syntax?
    while(a=8)



vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


© Markt+Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH