Stand: 17.03.2024
Lernziele
- Einfache JavaScript-Programme mit Hilfe von Variablen, Kontrollstrukturen (If, Schleifen) und Funktionen schreiben
- Einfache Beispiele für funktionales Programmieren anwenden können (z.B. forEach)
- Umgang mit assoziativen Arrays (Listen) in JavaScript beherrschen
- Obekte in JavaScript erstellen und verwenden
Dieses Kapitel ist eine Einführung in die Programmiersprache JavaScript. Zielgruppe sind Studierende, die bereits eine objektorientierte Programmiersprache kennen, vorzugsweise Java.
Begleitend zu diesem Kapitel können Sie sich auch hier noch weiter informieren:
- State of JavaScript: Ergebnisse einer Umfrage unter Webentwickler*innen, welche Sprachversionen, Frameworks und Tools am meisten genutzt werden.
4.1 Hintergrund
JavaScript ist die dominante Programmiersprache in der Webentwicklung, besonders im Frontend-Bereich. Eine spannende Entwicklung ist, dass JavaScript auch immer mehr im Backend-Bereich benutzt wird (besonders durch das Node.js-Framework), so dass es sich für Webentwickler*innen doppelt lohnt, sich mit JavaScript zu beschäftigen.
In diesem Kapitel geht es um die Sprache an sich. Wie die Sprache dann in Webseiten verwendet werden kann, lernen wir im nächsten Kapitel.
4.1.1 JavaScript und ECMAScript
Man sollte wissen, dass JavaScript "nur" eine mögliche Implementierung einer ideellen Sprachdefinition namens ECMAScript ist. Es ist immer eine gute Idee, Konzept und Implementierung zu trennen. Nur so kann man verhindern, dass reine Implementationsaspekte die Weiterentwicklung treiben und nur so kann man zulassen, dass es mehrere unabhängige Implementierungen geben kann.
Warum muss man das wissen? Die Entwicklung von ECMAScript ist der Realisierung von JavaScript-Engines (s. u.) voraus. Derzeit liegt ECMAScript in Version 14 vor (seit Juni 2023). Wenn man wissen will, welche Sprach-Features ein Browser (in seinen verschiedenen Update-Versionen) unterstützt, muss man schauen welche ECMAScript-Version unterstützt wird. Hierfür können wir Ihnen die Seite "Can I Use" empfehlen. Dort können Sie u. a. für die einzelnen ECMAScript-Features prüfen, ob diese von den verschiedenen Browsern unterstützt werden. Sie können auch einsehen, welche Änderungen es beim ECMAScipt-Update gab, z. B. bei ES2024. Wenn man wissen will, in welche Richtung sich JavaScript entwickeln wird, kann man sich die höheren Versionen bereits jetzt ansehen.
Einige relevante Artikel zum Thema:
- ECMAScript Versionen (Wikipedia)
- JavaScript 2023 (w3schools)
- ECMAScript (Wikipedia)
- JavaScript (Wikipedia)
4.1.2 JavaScript-Engines
Bei Programmiersprachen unterscheidet man zwischen Sprachen, die von einem Compiler übersetzt werden (z. B. C++), und Sprachen, die von einem Interpreter übersetzten werden (z. B. JavaScript, Python, PHP). Der Unterschied besteht darin, dass ein Compiler den Code einmalig in Maschinensprache übersetzt und ab dann immer nur der Maschinencode ausgeführt wird. Ein Interpreter hingegen übersetzt während das Programm läuft immer jeweils die aktuelle Code-Zeile und führt diese aus. Beide Ansätze haben Vor- und Nachteile.
Fun Fact: Bei Java wird eine Mischung verwendet; der Java-Code wird zunächst in Bytecode (nur "fast" Maschinencode) compiliert und dieser Bytecode wird dann für jeden Programmlauf von einem Interpreter, der Java Runtime Engine (JRE), ausgeführt.
Die JavaScript-Engine ist die Software, die JavaScript übersetzt und/oder ausführt. JavaScript ist ursprünglich eine interpretierte Sprache, aber moderne Engines verfolgen den Compiler-Ansatz, um noch mehr Performance rauszuholen.
Da JavaScript in der Regel im Browser ausgeführt wird, hat jeder Browser eine eigene Engine, z. B.
- Chrome und Edge: V8
- Firefox: SpiderMonkey
- Safari: JavaScriptCore
V8 ist die derzeit am weitesten verbreitete Engine (wird z. B. auch von Node.js und im Opera-Browser verwendet). Die Engine stammt von Google und ist open source. Tatsächlich wird hier der Code nicht interpretiert, sondern compiliert, um eine höhere Performance zu erreichen.
Vorsicht Verwechselungsgefahr: Im Gegensatz zur JavaScript-Engine ist die Browser-Engine dafür verantwortlich, HTML/CSS umzusetzen (Layout und Rendering). Man muss etwas aufpassen, dass man diese beiden nicht verwechselt. Bekannte Browser-Engines sind Gecko (Firefox), WebKit (Safari) und Blink (Chrome).
4.2 Code schreiben und ausführen
Wir stellen hier zwei Möglichkeiten vor, um in JavaScript-Code zu schreiben und den Code auszuführen:
- Mit einem Texteditor (z. B. VS Code) Code schreiben und den Code in einem Browser ausführen
- Beides in einer Programmierumgebung (IDE: Integrated Development Environment) wie WebStorm erledigen
Beides hat Vor- und Nachteile. Im Hinterkopf sollte man behalten, dass (fast) jeder JavaScript-Code letztlich in einem Browser läuft und dort getestet werden muss.
4.2.1 JavaScript mit Editor und Browser
Jeder Browser "versteht" JavaScript. Das können wir ausnutzen, indem wir eine einfache HTML-Seite erstellen und dort unseren JavaScript-Code einbetten.
Den Code testen wir, indem wir die Seite in einem Browser öffnen und im Browser eine Konsole öffnen, um Ausgaben und Fehlermeldungen zu sehen. Um die HTML-Seite zu erstellen, verwenden wir wie gewohnt einen Editor wie VS Code.
Einbetten
Um JavaScript in eine Webseite - also eine HTML-Datei - einzubauen, verwenden Sie das <script>
-Element. In dieses Element fügen Sie JavaScript-Code hinein, z. B. eine einfache Konsolenausgabe (die Konsolenausgabe erklären wir im Abschnitt "Erste Schritte"):
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8"/>
<title>JavaScript</title>
</head>
<body>
<p>JavaScript running...</p>
<script>
console.log("Hello, world");
</script>
</body>
</html>
Konsole
Aber wo sehen Sie die Ausgabe? Laden Sie die HTML-Datei in Ihrem Browser (sollte mit Drag'n Drop gehen) und öffnen Sie die JavaScript-Konsole. Diese finden Sie
- in Chrome unter Anzeigen > Entwickler > JavaScript-Konsole
- in Firefox unter Extras > Web-Entwickler > Web-Konsole
(Diese Begriffe ändern sich von Zeit zu Zeit, also evtl. nach ähnlichen Bezeichnungen suchen.)
Hier sehen Sie die HTML-Datei ohne Konsole in Chrome:
Wenn Sie die Konsole öffnen, erscheint sie rechts:
Die Konsole kann z. B. auch unten angezeigt werden, in Firefox sieht das dann so aus:
Der Nachteil dieser Vorgehensweise ist offensichtlich, dass Sie mit zwei Tools arbeiten (Editor und Browser). Wenn Sie den Code ändern, reicht im Browser ein Reload, um die Änderung zu sehen (hier lohnt es sich, den Tastaturkürzel für Reload zu verinnerlichen).
Der Vorteil ist, dass Sie im Browser genau dort testen, wo Ihr Code später auch zum Einsatz kommt.
4.2.2 JavaScript mit der Entwicklungsumgebung WebStorm
WebStorm ist eine integrierte Entwicklungsumgebung der Firma JetBrains, die auch IntelliJ IDEA für Java entwickelt haben. Diese Umgebung ist kostenpflichtig, aber für Studierende und Lehrende frei nutzbar.
Der Vorteil gegenüber der Methode "Editor + Browser" ist, dass Sie nicht ständig zwischen Editor und Browser wechseln müssen. In WebStorm haben Sie ein Code-Fenster und ein Konsolen-Fenster. Wenn Sie auf "Run" drücken, sehen Sie die Ausgaben im Konsolen-Fenster.
Der Nachteil ist, dass WebStorm, sobald Sie es professionell einsetzen, kostenpflichtig wird und dass Sie letztlich doch immer nochmal im Browser testen müssen.
Am Rande sei bemerkt, dass WebStrom weit mehr kann, als nur JavaScript-Code zu testen, und für die Entwicklung komplexer Webprojekte verwendet wird. Aber auch VS Code bietet, durch sogenannte Extensions, mittlerweile einige Funktionen einer IDE an.
Oberfläche
In der Abbildung unten sehen Sie das Code-Fenster (rechts-oben) und die Konsole (unten). Links oben sehen Sie den Projektbereich mit Verzeichnisstruktur und Dateien.
Lizenz und Download
Auf der Webseite von WebStorm finden Sie unter dem Punkt For students and teachers die Möglichkeit, eine freie Lizenz als Student*in zu bekommen.
Erster Test
Für einen ersten Test tun Sie folgendes:
- Erstellen Sie ein neues Projekt unter File > New > Project..; wählen Sie "Empty Project".
- Erstellen Sie eine neue Datei unter File > New > JavaScript File.
- Führen Sie den Code in dieser Datei aus mit Run > Run...
Haben Sie eine Datei einmal ausgeführt, können Sie mit dem grünen Play-Button (rechts-oben in der Toolbar) die Datei wiederholt ausführen.
4.2.3 Erste Schritte
Konsole und Konsolenausgabe
Eine Konsole ist ein Ausgabebereich für Textmeldungen. Solche Ausgaben werden im Grunde nur während der Programmentwicklung genutzt, um Infos zum laufenden Programm auszugeben. In JavaScript verwenden Sie console.log()
:
console.log('hello world');
Sie können in JavaScript meist zwischen doppelten und einfachen Anführungszeichen wählen. Es funktioniert also auch:
console.log("hello world");
Eine interessante Variante ist die Gruppierung von Konsolenausgaben, wenn Sie z. B. viele oder sehr lange Ausgaben in Ihrem Programm haben. Alle Ausgaben dieser Gruppierung werden dann zunächst eingeklappt dargestellt und können bei Bedarf aufgeklappt werden.
Sie können mit einer Bezeichnung Ihrer Wahl mit
console.group('Schleifentest');
eine Gruppe eröffnen. Dann schreiben Sie normal auf die Konsole:
console.log('1');
console.log('2');
console.log('3');
Danach schließen Sie die Gruppe mit
console.groupEnd();
Kommentare
Kommentare funktionieren wie in Java.
Es gibt den Zeilenkommentar, der alles ab //
ignoriert:
// Das ist ein Kommentar .. console.log('hello world'); // .. das auch
Und es gibt den Blockkommentar, der mehrere Zeilen umfassen kann. Er beginnt mit /*
und endet mit */
:
/* Das ist ein Kommentar, der über mehrere Zeilen geht. */ console.log('hello world');
4.3 Datenstrukturen
4.3.1 Variablen und Typen
Variablen in JavaScript funktionieren prinzipiell ähnlich wie in Java, aber der Umgang mit Typen ist wesentlich lockerer, d. h. Sie können in der Regel die Angabe von Typen weglassen.
4.3.2 Globale Variablen
Wenn Sie eine Variable "foo" erstellen wollen, schreiben Sie folgende Deklaration mit dem Schlüsselwort var
:
var foo;
Sie erzeugen so eine neue globale Variable.
Solange Sie keinen eigenen Wert zugewiesen haben, enthält die Variable einen speziellen Wert, den JavaScript als undefined
bezeichnet. Da wir hier keinen Typen angegeben haben, kann JavaScript nicht einfach einen Wert wie 0 oder false zuweisen, da diese Werte ja vom Typ abhängen.
Sie können bei der Deklaration auch gleich einen Wert zuweisen (das nennt man auch Initialisierung):
var foo = 10;
Das Schlüsselwort var
können Sie auch weglassen:
foo = 10;
Lokale Variablen und Konstanten (ES6)
Seit ECMAScript 6 gibt es statt var
auch let
:
let foo;
Der Unterschied ist, dass mit var
eine Variable global angelegt wird, wohingegen das let
eine lokale Variable erstellt, wie es in der Regel erwünscht ist.
Mit const
kann man eine Konstante deklarieren (ähnlich wie mit dem Schlüsselwort "final" in Java), d. h. die Variable darf im weiteren Programmverlauf nicht verändert werden:
const pi = 3.14159;
Implizite Deklaration
Wie man oben sieht, müssen Sie sich nicht entscheiden, ob z. B. eine Zahl oder ein String hineinkommt. Bei der ersten Zuweisung entscheidet JavaScript einfach aufgrund des Werts, welchen Typ es nimmt. Man spricht auch von impliziter Deklaration.
foo = 10;
Weitere Beispiele für Variablen:
x = 100; y = 80; distance = 43.8; isActive = false; name = "Sally"; name2 = 'Harry'; // String mit einfachen Anführungszeichen
Beachten Sie, dass Sie bei Strings sowohl die einfachen als auch die doppelten Anführungszeichen verwenden können.
Dynamische Typisierung
In JavaScript können Sie sich jederzeit umentscheiden und den Typ einer Variablen ändern. Man sagt daher auch, JavaScript ist dynamisch typisiert
foo = 10; // hier soll eine Zahl rein foo = "Harry"; // äh... doch nicht
Sie können den Typ einer Variablen beliebig oft ändern. Dynamische Typisierung kommt auch bei Arrays zum Tragen, wo sie besonders nützlich ist.
Typen
JavaScript hat dennoch Typen und zwar die folgenden:
- string
- number
- boolean
- object
- function
- undefined
Sie finden den Typ mit typeof
:
a = 25;
typeof(a);
ergibt
"number"
Oder direkt mit einem Wert
typeof("hallo");
ergibt
"string"
Bei Zahlen (number) verwendet JavaScript immer Gleitkommazahlen mit doppelter Präzision (8 Byte), entspricht also dem Datentyp double in Java.
4.3.3 Strings
Strings funktionieren ähnlich wie in Java. Man kann Strings mit einfachen oder doppelten Anführungszeichen kennzeichnen und Variablen zuweisen. Wie in Java können mehrere Strings mit dem Operator +
zusammengefügt werden (String-Konkatenation).
s1 = "hallo"; s2 = 'welt'; s3 = s1 + " " + s2; console.log(s3); // hallo welt
Strings sind, wie in Java, Objekte. Die Länge des Strings steht in der Eigenschaft length
:
s = "Peter"; console.log(s.length); // 5
Wie in Java stehen Ihnen für wichtige Aufgaben wie das Suchen, Teilen und Zusammenfügen von Strings Methoden zur Verfügung, die Sie per Punktnotation aufrufen.
Groß-/Kleinschreibung
Groß-/Kleinschreibung ändern Sie mit den Methoden toLowerCase()
und toUpperCase()
:
str = "Hallo Welt"; console.log(str.toLowerCase()); // hallo welt console.log(str.toUpperCase()); // HALLO WELT
Beachten Sie, dass diese Methoden neue Strings zurückgeben und nicht etwa den bestehen String ändern.
Suchen
Die Methode indexOf()
gibt wie in Java die Stelle (Zahl) zurück, an der der Suchstring gefunden wurde. Die Methode includes()
entspricht der Java-Methode contains(), gibt also einen booleschen Wert zurück, der anzeigt, ob der Teilstring überhaupt enthalten ist.
text = "I expect you to die, Mister Bond."; console.log(text.indexOf("you")); // 9 console.log(text.includes("Bond")); // true
Schneiden
Wie in Java gibt es die Methode substring()
, um einen Teilstring herauszuschneiden. Die Methode gibt diesen Teilstring als neuen String zurück. Wie in Java, wird das Original nicht verändert.
Die Methode gibt es mit einem oder zwei Parametern. Der erste Parameter gibt die Startstelle an (inklusive) und der zweite die Endstelle (exklusive).
str = 'james bond';
console.log(str.substring(0, 5)); // james
Wird der zweite Parameter weggelassen, wird bis zum Ende geschnitten.
console.log(str.substring(6)); // bond
Trimmen
Die Methode trim()
entfernt alle führenden und anhängigen Leerzeichen.
str = "Haustür"; console.log(str.substring(0, 4)); // Haus console.log(str.substring(4)); // tür input = "Name: James Bond "; name = input.substring(5).trim(); console.log(name); // "James Bond"
Auch hier wird ein neuer String zurückgegeben.
Zerlegen
Die Methode split()
erlaubt es, einen String anhand eines frei definierbaren Trennzeichen in mehrere Teile zu zerlegen. Die Teile liegen dann als Array vor.
input = "Peter,Paul,Mary"; parts = input.split(","); console.log(parts); // ["Peter", "Paul", "Mary"]
Im CSV-Dateiformat werden Daten z. B. mit Komma oder Semicolon getrennt und können mit Hilfe von split
verarbeitet werden.
4.3.4 Arrays
Zum Nachschlagen beim Thema Arrays schauen Sie in die JavaScript Array Reference.
Vergleicht man Arrays in JavaScript mit Arrays in Java, so sind die Ähnlichkeiten eher oberflächlich (Notation mit eckigen Klammern). Ansonsten funktionieren JavaScript-Arrays eher wie Listen, denn im Gegensatz zu Java-Arrays kann ein JavaScript-Array:
- seine Länge jederzeit ändern
- Inhalte verschiedener Typen enthalten
Einen neuen, leeren Array erstellen Sie mit:
a = [];
Sie können einen Array direkt mit Werten initialisieren. Diese Werte können unterschiedlichen Typs sein:
b = ["Joe", "Moe", "Zoe"]; // Array mit Strings
c = [1, "zwei", 3.5]; // Werte unterschiedlichen Typs
Der Zugriff auf die Inhalte sieht genauso aus wie in Java:
console.log(b[0]); // gibt "Joe" aus
Und natürlich können Sie die Werte auch durch Zuweisung verändern:
c[0] = b[2]; // setzt erstes Element von c auf "Zoe"
Neue Werte fügen Sie mit push()
hinzu. Die Werte werden dem Array ans Ende angefügt. Sie verlängern den Array also um einen Wert.
b.push("Cloe"); // ["Joe", "Moe", "Zoe", "Cloe"] c.push(4); // [1, "zwei", 3.5, 4]
Die Operation pop()
gibt das letzte Element zurück und entfernt dieses, verkürzt also den Array um einen Wert. Zusammen realisieren push/pop die Funktionsweise eines Stacks oder Stapels.
a = [1, 3, 5];
el = a.pop(); // bekommt 5, a wird zu [1, 3]
Zwei ähnliche Methoden sind shift()
und unshift()
. Sie betreffen das erste Element, nicht das letzte.
Arrays sind wie in Java Objekte und haben wie in Java sowohl Methoden (Funktionen) als auch Eigenschaften. Eigenschaften sind Variablen, die zum Objekt gehören und auf die man per Punktnotation zugreifen kann.
Eigenschaften und Methoden
Ein Array ist wie in Java ein Objekt. Somit hat ein Array Eigenschaften und Methoden, die über Punktnotation aufgerufen werden.
Die Länge eines Arrays erhalten Sie mit der Eigenschaft length
:
console.log(b.length); // 4
Die Methode sort
sortiert die Elemente des Arrays. Beachten Sie, dass das Array dabei verändert wird:
a = [200, 300, 100];
a.sort();
console.log(a); // [ 100, 200, 300 ]
Die Sortierung ist nicht immer intuitiv:
a = [ "Sally", "Albert", "Camus", "z", "a"];
a.sort();
console.log(a); // [ 'Albert', 'Camus', 'Sally', 'a', 'z' ]
Die Methode join
baut alle Arrayelemente zu einem String zusammen. Man kann der Methode einen Trenn-String übergeben, der zwischen die Elemente gefügt wird.
a = [ "Sally", "Albert", "Camus"];
console.log(a.join("_")); // Sally_Albert_Camus
Die Methode slice
gibt einen Teilarray zurück. Dazu übergibt man zwei Parameter: den Index des ersten Elements und den Index des letzten Elements. Der zweite Index ist exklusiv, d. h. das entsprechende Element ist nicht im Ergebnis enthalten:
a = [ "Sally", "Albert", "Camus", "Ruth", "Herbert"];
console.log(a.slice(1,3)); // [ 'Albert', 'Camus' ]
Hier sieht man, dass "Ruth" (Index 3) nicht in der Ergebnismenge ist.
4.3.5 Assoziative Arrays
Bei Arrays speichern wir eine Reihe von Elementen, auf die wir mit Hilfe von Indexzahlen zugreifen können. Manchmal wollen wir aber nicht über Zahlen auf diese Elemente zugreifen, sondern z. B. über Wörter. Bei einem Telefonbuch zum Beispiel wollen wir zu einem Namen eine Nummer speichern. So etwas nennt man einen assoziativen Speicher. Andere Namen sind: Dictionary, Hashtabelle oder assoziativer Array (siehe auch Wikipedia).
In JavaScript können wir so ein Telefonbuch speichern. Sie sehen drei Paare, jedes Paar besteht aus einem Schlüssel (z. B. "Harry") und dem dazugehörigen Wert (bei "Harry" wäre das 123):
phonebook = { "Harry": 123, "Sally": 456, "Betty": 789 };
Man nennt diese Art der Zuordnung daher auch Key-Value-Paar (key, engl. für Schlüssel, und value, engl. für Wert).
Sie können den ganzen Array ausgeben mit:
console.log(phonebook);
{ Harry: 123, Sally: 456, Betty: 789 }
Der Zugriff erfolgt ähnlich wie bei Arrays über die eckigen Klammern: statt der Indexzahl gibt man jetzt den Schlüssel an und erhält den Wert zurück:
console.log(phonebook["Sally"]); // 456
Neue Werte fügt man durch einfache Zuweisung hinzu:
phonebook['Lonny'] = 555;
console.log(phonebook);
{ Harry: 123, Sally: 456, Betty: 789, Lonny: 555 }
Unerwünschte Einträge können mit delete
gelöscht werden.
delete phonebook['Harry'];
Die Werte müssen natürlich nicht Zahlen sein, sondern können auch boolesch sein:
vegetarian = { "Harry": true, "Sally": true, "Betty": false };
console.log(vegetarian["Betty"]); // false
Oder auch Strings:
favorite_color = { "Harry": "red", "Sally": "green", "Betty": "blue" };
console.log(favorite_color["Harry"]); // red
Sie können wie bei Arrays beliebige Typen mischen:
data = { "important": true, "name": "Bond", "id": 7 };
Und Sie können sich den ganzen Array ausgeben lassen:
console.log(data);
Für das Durchlaufen von assoziativen Arrays gibt es eine spezielle For-Schleife: die For-in-Schleife (siehe unten).
4.3.6 Mengen
Es gibt Fälle, da möchte man nicht zwei "gleiche" Elemente in einem Array haben. Oder anders gesagt: man möchte nur Unikate im Array speichern. Dafür gibt es seit ES6 in JavaScript das Konzept der Menge oder - auf Englisch - eines Sets.
Sie erstellen ein Set so:
let s = new Set();
So fügen Sie Elemente hinzu:
s.add('foo');
s.add('bar');
s.add('foo');
s.add('shoe');
s.add('foo');
Das Set hat nach diesen Anweisungen nur drei Elemente, da "gleiche" Element nicht hinzugefügt werden:
Set { 'foo', 'bar', 'shoe' }
Im Gegensatz zu Arrays können Sie im Set gezielt Elemente löschen:
s.delete('foo');
Sie können ein Set mit forEach
durchlaufen (s. u.):
s.forEach(x => console.log('Element: ' + x));
Element: bar Element: shoe
4.4 Kontrollfluss
4.4.1 If, Switch, ternärer Operator
If
Bedingte Anweisungen mit if
und else
sehen exakt so aus wie in Java.
p = 52; if (p > 50) { console.log("Prüfung bestanden"); } else { console.log("Leider durchgefallen"); }
Auch das else if
sollte vertraut sein:
p = 92; if (p > 90) { console.log("Prüfung exzellent bestanden"); } else if (p > 50) { console.log("Prüfung bestanden"); } else { console.log("Leider durchgefallen"); }
Switch
Und selbst die Fallunterscheidung mit switch
funktioniert wie in Java:
wahl = 10; switch (wahl) { case 0: console.log("Sie kaufen den Koffer"); break; case 1: console.log("Sie kaufen den Toaster"); break; default: console.log("Sie kaufen nichts"); }
Ternärer Operator
Wie in Java gibt es auch in JavaScript den ternären Operator. Dieser ermöglicht die Auswahl zwischen zwei alternativen Werten aufgrund eines booleschen Ausdrucks. Haben wir z. B. die Variable:
let haveTime = true;
können wir aufgrund des booleschen Werts zwischen zwei Strings entscheiden:
console.log("Heute passt es " + (haveTime ? "sehr gut" : "leider nicht"));
Der ternäre Operator ist in solchen Fällen deutlich schlanker als ein If.
4.4.2 Bedingungen
Wie in Java...
Für If, Switch und Schleifen müssen Sie Bedingungen formulieren. Diese Bedingungen werden genauso wie in Java formuliert. Es gibt die beiden Literale
true
false
Sie können numerische Vergleiche durchführen
x >= 50
und Sie können die logischen Operatoren UND &&
, ODER ||
und NICHT !
verwenden, z. B.
x > 50 && x < 100
Wie in Java müssen Sie die Präzedenz beachten (NICHT vor UND vor ODER) und können Klammern einsetzen, um die Ausführungsreihenfolge eines logischen Ausdrucks zu steuern.
Bei Gleichheit gibt es in JavaScript das doppelte Gleichheitszeichen ==
und das dreifache Gleichheitszeichen ===
. Bei dem doppelten Gleichheitszeichen wird der Datentyp ignoriert, d. h. die folgenden Bedingungen sind wahr
5 == "5"
5 == 5
Nicht wie in Java...
Bei dem dreifachen Gleichheitszeichen muss zusätzlich der Typ übereinstimmen, d. h. diese Bedingung ist nicht wahr:
5 === "5" // false
Beachten Sie, dass JavaScript nicht zwischen ganzen Zahlen und Gleitkommazahlen unterscheidet, so dass beide folgenden Bedingungen wahr sind:
5 == 5.0
5 === 5.0
Im Gegensatz zu Java, kann man in JavaScript auch nicht-boolesche Werte als Bedingung verwenden. Dabei gilt:
- Bei Zahlen wird die 0 als
false
und alles andere alstrue
interpretiert - Bei Strings wird der leere String als
false
und alle nicht-leeren Strings alstrue
interpretiert - der Wert
undefined
wird alsfalse
interpretiert
Sie können das ausprobieren mit
if (0) {
console.log('true');
} else {
console.log('false');
}
x = 5;
if (x) {
console.log('true');
} else {
console.log('false');
}
if ('foo') {
console.log('true');
} else {
console.log('false');
}
if ('') {
console.log('true');
} else {
console.log('false');
}
if (undefined) {
console.log('true');
} else {
console.log('false');
}
4.4.3 Schleifen
Eine For-Schleife sieht so aus wie in Java, nur dass bei der Laufvariablen kein Datentyp steht:
for (i = 0; i < 3; i++) { console.log("hello"); // wird 3x ausgeführt }
Noch sauberer ist es, wenn man bei der Laufvariablen ein let
voranstellt, um klar zu stellen, dass i
eine lokale Variable ist:
for (let i = 0; i < 3; i++) { console.log("hello"); // wird 3x ausgeführt }
Im ersten Fall können Sie hinter der Schleife noch auf i
zugreifen, im zweiten Fall nicht.
4.4.4 Schleifen und Arrays
Auch in JavaScript sind Arrays und Schleifen perfekte Partner, da wir sehr elegant mit einer Laufvariablen von 0 bis zur Länge des Arrays minus eins laufen können:
b = ["Joe", "Moe", "Zoe"]; for (i = 0; i < b.length; i++) { console.log(b[i]); }
Bei Arrays nutzt man in JavaScript auch sehr häufig das forEach (siehe unten).
Bei einem assoziativen Array haben wir bei einer regulären For-Schleife das Problem, dass wir mit einer Indexzahl als Laufvariablen nicht auf die Inhalte zugreifen können. Daher gibt es die For-in-Schleife.
Assoziative Arrays mit For-in
Bei assoziativen Arrays haben wir Schlüssel und Werte.
data = { "important": true, "name": "Bond", "id": 7 };
In JavaScript benutzen wir daher die for-in-Schleife. Diese Schleife durchläuft die Schlüssel:
for (k in data) {
console.log(k);
}
Wir können natürlich den Schlüssel nutzen, um den jeweiligen Wert zu beziehen:
for (k in data) {
console.log("Schlüssel " + k + " hat Wert " + data[k]);
}
4.5 Funktionen
Eines der "Killer-Features" von JavaScript ist die Möglichkeit der funktionalen Programmierung. Damit ist u. a. gemeint, dass Funktionen in Variablen gespeichert und durch Parameterübergabe "herumgereicht" werden können. Man kann also in vielen Situationen kleine (oder große) Stückchen Code weiterreichen oder anhängen. Wie nützlich sowas ist, haben Sie vielleicht bei der GUI-Programmierung in JavaFX gesehen (Stichwort "Lambda-Ausdrücke"). Technisch funktioniert das so, dass Funktionen in JavaScript als Objekte gespeichert werden.
Aber fangen wir vorn an.
4.5.1 Deklaration, Parameter, Rückgabe
Funktionen werden im einfachsten Fall global deklariert (ähnlich wie in Processing) und sind anschließend überall aufrufbar. Dies funktioniert über das Schlüsselwort function
.
Eine einfache Funktion sowie ihr Aufruf:
// Deklaration function printOne() { console.log(1); } // Aufruf printOne(); // Ausgabe: 1
Eine Funktion mit einem Parameter. Auch bei Parametern wird - wie bei Variablen - kein Datentyp angegeben:
function sayHello(name) { console.log("Hello, " + name); } sayHello("Peter"); // Hello, Peter
Mehrere Parameter sind natürlich möglich und werden durch Komma getrennt.
Eine Funktion kann auch einen Rückgabewert haben. Wie in Java verwenden wir dazu das Schlüsselwort return
. Im Gegensatz zu Java wird aber kein Rückgabetyp angegeben:
function sum(a, b, c) { return a + b + c; } console.log(sum(5, 10, 100)); // 115
Optionale Parameter
Wird eine Funktion mit weniger Parametern aufgerufen als in der Definition angegeben, so werden die Parameter, die nicht abgedeckt sind, mit "undefined" belegt. (Wird eine Funktion mit mehr Parametern als definiert aufgerufen, werden die überzähligen Parameter einfach ignoriert.)
Sie können das nutzen, um optionale Parameter zu definieren, wie hier Parameter "b":
function onetwo(a, b) {
console.log("one: " + a);
if (b != undefined) {
console.log("two: " + b);
}
}
Jetzt können Sie gefahrlos folgende Aufrufe programmieren:
onetwo("Harry");
onetwo("Harry", "Sally");
Variable Parameterzahl
Innerhalb einer Funktion gibt es automatisch eine Variable arguments
, die alle übergebenen Parameter enthält, auch wenn es "zu viele" Parameter beim Aufruf gab. Diese Variable ist ein Array, der alle übergebenen Werte enthält. Sie können diesen Array nutzen, um Funktionen mit einer variablen Parameterzahl zu definieren:
function summe() {
let s = 0;
for (let i = 0; i < arguments.length; i++) {
s += arguments[i];
}
return s;
}
Diese Funktion können Sie mit beliebig vielen Werten aufrufen. So sind etwa folgende Aufrufe möglich:
console.log(summe()); // 0
console.log(summe(42, -10)); // 32
console.log(summe(1, 2, 3)); // 6
Alternativ kann man natürlich auch mit einem Array als expliziten Parameter arbeiten.
4.5.2 Anonyme Funktionen
Eine weitere Möglichkeit, Funktionen zu erschaffen, ist, zunächst eine anonyme Funktion zu definieren (anonym heißt: die Funktion hat keinen Namen), und diese Funktion dann an eine Variable zu heften.
Hier eine "normale" Funktion mit Schlüsselwort function
und dem Namen der Funktion (printOne):
function printOne() {
console.log(1);
}
Jetzt definieren wir eine anonyme Funktion. Hier lassen wir den Namen einfach weg. Dafür weisen wir die resultierende anonyme Funktion (ein Objekt) der Variablen "printOne" zu:
var printOne = function () {
console.log(1);
}
Der Aufruf ist in beiden Fällen:
printOne();
Ebenso können Sie Funktionen mit Parametern und Rückgabewert verfahren.
Callbacks
Warum soll das interessant sein? Ganz einfach: Sie können jetzt Funktionen "herumreichen", genauso wie Variablenwerte. Das wird insbesondere für Callbacks verwendet, wenn z. B. nach Ausführung einer Animationsfunktion foo
eine andere Funktion bar
aufgerufen werden soll, dann übergibt man der Funktion foo
die Funktion bar
als weiteren Parameter:
foo(1000, bar);
Oder man definiert die Callback-Funktion direkt hinein:
foo(1000, function () { console.log("finished"); });
Wir können uns das am Beispiel der Funktion setTimeout
ansehen. Die Funktion bekommt zwei Parameter: (1) eine Funktion, die nach einer gewissen Dauer D ausgeführt werden soll und (2) die Dauer D in Millisekunden.
Wollen Sie einfach den String "one" nach zwei Sekunden ausgeben:
setTimeout(function () {
console.log('one');
}, 2000);
Sie können sich den Timeout-Effekt z. B. mit diesem Code ansehen:
setTimeout(function () {
console.log('one');
}, 2000);
setTimeout(function () {
console.log('two');
}, 1000);
Sie sollten sehen:
two one
Funktionen tauschen
Ein weiteres Beispiel: Sie können die Funktion printOne
von oben auch an eine andere Variable binden:
var foo = printOne();
Und dann aufrufen:
foo();
Sie können so im Verlauf Ihres Programms die "Bedeutung" einer Funktion ändern:
var halloW = function (name) { console.log("Hallo, Frau " + name); } var halloM = function (name) { console.log("Hallo, Herr " + name); } gruss = halloM; gruss("Max Meier"); gruss = halloW; gruss("Maria Müller");
Funktionen werden also als "ein Stück Funktionalität" gesehen. Diese Stücke können beliebig vertauscht und auch als Parameter übergeben werden.
Kurzschreibweise als Arrow Function
Seit ECMAScript 6 können Sie eine neue, sehr kompakte Schreibweise verwenden.
Statt
myPrint = function (x) {
console.log(x);
}
schreiben Sie
myPrint = (x) => console.log(x);
oder (besonders wenn Sie mehr Code haben):
myPrint = (x) => {
console.log(x);
}
Mehrere Parameter werden durch Komma getrennt. Gibt es keine Parameter, schreibt man leere Klammern.
Unser Beispiel oben mit dem Timeout:
setTimeout(function () {
console.log('one');
}, 2000);
sieht in der Kompaktschreibweise so aus:
setTimeout(() => console.log('one'), 2000);
Beispiel sort()
Die Funktion sort
erlaubt es, einen Array zu sortieren:
a = [ 3, 1, 2 ];
a.sort();
console.log(a);
[ 1, 2, 3 ]
Wenn Sie eine andere Form der Sortierung haben möchten, können Sie sort
auch eine Funktion mitgeben. Diese Funktion vergleicht zwei Elemente a und b und gibt (1) eine negative Zahl zurück, wenn a kleiner b ist, (2) Null zurück, wenn beide gleich sind oder (2) eine positive Zahl zurück, wenn a größer b ist.
Die "eingebaute" Vergleichsfunktion (für Zahlen) sieht so aus:
function compare(a, b) {
return a - b;
}
Jetzt können Sie auch eine eigene Funktion definieren, die die Reihenfolge umdrehen soll:
function mycompare(a, b) {
return b - a;
}
Um die Funktion bei sort
anzuwenden, übergeben Sie sie als Parameter:
a = [ 3, 1, 2 ];
a.sort(mycompare);
console.log(a);
[ 3, 2, 1 ]
Alternativ können Sie die Funktion direkt bei Aufruf von sort
anonym definieren:
a.sort(function(a, b) { return b - a; });
Oder in der Kurzschreibweise:
a.sort((a, b) => {return b - a; } );
4.5.3 Arrays durchlaufen mit forEach
Für Arrays gibt es in JavaScript die Methode forEach
(Vorsicht: die Methode gibt es nicht für assoziative Arrays).
Die Methode wird auf dem Array aufgerufen:
a = ['Peter', 'Paul', 'Mary'];
a.forEach(...); // hier fehlt noch Code
Die Methode bekommt eine Funktion übergeben, die einen Parameter haben sollte. Diese Funktion wird dann für jedes Element im Array aufgerufen, wobei das jeweilige Element als Parameter übergeben wird.
In nächsten Beispiel definieren wir die Funktion sayHello
mit Parameter x
vorab und übergeben sie dem forEach
. Die Funktion wird dann für jedes der drei Elemente aufgerufen, wobei das x
jeweils das aktuelle Element repräsentiert.
a = ['Peter', 'Paul', 'Mary'];
var sayHello = function (x) {
console.log("Hello, " + x);
};
a.forEach(sayHello);
Noch üblicher ist es, dem forEach
eine anonyme Funktion zu übergeben, denn eigentlich benötigen wir den Namen der Funktion nicht; die Funktion wurde ja ausschließlich für das forEach
geschaffen.
Der Code wird so sehr kompakt:
a.forEach(function (name) {
console.log("Hello, " + name);
});
Wenn wir die Kompaktschreibweise verwenden:
a.forEach((n) => console.log("Hello, " + n));
Hier ein Beispiel, wo wir einen zweiten Array befüllen:
a = ['Peter', 'Paul', 'Mary'];
b = [];
a.forEach((x) => b.push('Agent ' + x));
console.log(b);
[ 'Agent Peter', 'Agent Paul', 'Agent Mary' ]
Eine weitere typische Aufgabe ist die Summierung von Zahlen:
a = [ 10, 50, 40 ];
s = 0;
a.forEach((x) => s+=x);
console.log(s);
100
Für assoziative Arrays müssen Sie die For-in-Schleife verwenden.
4.6 Objekte
In JavaScript gibt es Objekte, aber keine Klassen. Jeder, der Java kennt, müsste jetzt ins Grübeln kommen. In Java definiert man doch erst eine Klasse als eine Art Bauplan für Objekte. Wenn ich Autos speichern will, definiere ich eine Klasse Auto mit den Eigenschaften firma (String), modell (String) und kilometerstand (int) zum Beispiel. Erst dann kann ich Objekte (Instanzen) durch Instanziierung - Schlüsselwort new
- erzeugen. In JavaScript gibt es keine Klassen, also auch keine Baupläne. Jedes Objekt wird individuell zusammengestellt.
4.6.1 Objekte und Eigenschaften
Ein Objekt in JavaScript ist einfach nur eine Ansammlung von Eigenschaften, die wir einer Variablen zuweisen:
let a1 = {
firma: "VW",
modell: "Golf",
kilometerstand: 11032
}
In der Tat handelt es sich um einen assoziativen Array. Die Eigenschaften sind die Schlüssel, die jeweils einen Wert haben.
Da Sie hier keine Klasse als "Bauplan" haben, hindert Sie niemand daran, beim nächsten Objekt andere Eigenschaften zu wählen oder die Eigenschaften anders zu benennen.
let a2 = {
typ: "Audi",
variante: "A4",
kilometer: 0
}
Diese Freiheit birgt natürlich das Risiko, dass Sie unabsichtlich eine Eigenschaft "falsch" nennen.
null
In JavaScript gibt es wie in Java den Bezeichner null
, um anzuzeigen, dass eine Variable "eigentlich" einen Wert haben sollte, aber eben gerade keinen hat.
Sie können null
zum Beispiel als Rückgabeoption verwenden, wenn eine Suchfunktion nicht findet.
Sie verwenden null
ähnlich wie in Java als Wert:
let meinobjekt = null;
null
wird nicht nur in Zusammenhang mit Objekten verwendet, ist aber hier besonders relevant.
Punktnotation
Auf die Eigenschaften des Objekts a1
können Sie mit Punktnotation zugreifen:
console.log(a1.firma);
console.log(a1.modell);
console.log(a1.kilometerstand);
Objekt mit Eigenschaften befüllen
Sie können über Punktnotation auch neue Eigenschaften hinzufügen:
a1.farbe = "rot";
Jetzt können Sie ein Objekt auch zunächst als "leeres Objekt" erzeugen und später mit Eigenschaften "befüllen". Auch hier sieht man keinen Unterschied zu einem leeren assoziativen Arrray:
a3 = {}; // neues leeres Objekt
Anschließend fügen Sie nacheinander Eigenschaften hinzu:
a3.firma = "Audi"; // neue Eigenschaft "firma"
a3.modell = "A6"; // neue Eigenschaft "modell"
a3.kilometerstand = 0; // neue Eigenschaft "kilometerstand"
Bei jeder Zuweisung auf eine unbekannte Eigenschaft, wird die nicht vorhandene Eigenschaft einfach erzeugt.
Bei der Ausgabe mit console.log(a3)
sieht das Objekt tatsächlich wie ein assoziativer Array aus:
{firma: "Audi", modell: "A6", kilometerstand: 0}
Eigenschaften über eckige Klammern zugreifen
Da ein Objekt ein assoziativer Array ist, können wir auf die Eigenschaften (= Schlüssel) auch mit Hilfe eckiger Klammern zugreifen. Dies ist neben Punktnotation eine zweite Möglichkeit, auf Eigenschaften zuzugreifen:
console.log(a1['firma']);
console.log(a1['modell']);
Der Vorteil dieser Methode ist, dass die Eigenschaft auch als Variable vorliegen kann. Das werden wir später unter "Eigenschaften auflisten" noch sehen...
Eigenschaften löschen
Sie können auch im Programm eine Eigenschaft wieder löschen:
delete a1.farbe;
Dies betrifft offensichtlich nur das adressierte Objekt.
Eigenschaften testen
Da Sie Objekte jederzeit um Eigenschaften und Methoden erweitern können, benötigen Sie manchmal Mechanismen, um zu testen, ob ein Objekt eine bestimmte Eigenschaft hat.
Mit dem Schlüsselwort in
können Sie testen, ob ein Objekt eine bestimmte Eigenschaft oder Methode hat.
Für unser Objekt a1
:
let a1 = {
firma: "VW",
modell: "Golf",
kilometerstand: 11032,
}
Wir können jetzt testen:
console.log('firma' in a1); // true
console.log('fahre' in a1); // true
console.log('kilometer' in a1); // false
Eigenschaften auflisten
Sie können mit einer erweiterten For-Schleifen alle Eigenschaften eines Objekts durchlaufen:
for (p in a1) {
console.log("Eigenschaft " + p);
}
Jede Eigenschaft wird als String zurückgegeben.
Wenn man zusätzlich den Wert ausgeben möchte, kann man dies über die Notation mit eckigen Klammern tun:
for (p in a1) {
console.log("Eigenschaft " + p + " hat Wert " + a1[p]);
}
4.6.2 Methoden
Sie können auch Funktionen (Methoden) in das Objekt packen.
let a1 = { firma: "VW", modell: "Golf", kilometerstand: 11032, fahre: function() { console.log("brumm brumm"); } }
Die Methode fahre()
gehört zu Objekt a1
. Auch hier erfolgt der Aufruf mit Punktnotation:
a1.fahre();
Auch bei Methoden können Sie eine Methode hinzufügen, indem Sie einfach eine nicht vorhandene Eigenschaft mit einer anonymen Funktion belegen:
a2.fahre = function() { console.log("vrooooooom"); }
Hier wird auch deutlich, dass die zwei Objekte a1
und a2
unterschiedlich sind: die Methode fahre()
hat jeweils andere Ausgaben.
Seien Sie sich auch bewusst, dass niemand Sie daran hindert, die Eigenschaften unterschiedlich zu benennen (bei einem Objekt "firma", beim nächsten "hersteller") oder bei einem Objekt mehr oder weniger Eigenschaften zu definieren. Das ist durchaus ein Nachteil, weil durch Tippfehler etc. unfreiwillig Inkonsistenzen entstehen, denn es gibt keinen "Bauplan", keine Klasse. Vielleicht wird bei der Gelegenheit auch klar, warum die Idee von Klassen keine so schlechte ist.
Methodenverkettung
Wenn eine Methode ein Objekt zurückgibt, kann man direkt die nächste Methode aufrufen. Das nennt man auch Method Chaining.
Bei Strings wird dies gern verwendet. Die Methode substring
zerschneidet den String und gibt als Resultat einen neuen String zurück. Wollen wir diesen weiterverarbeiten - z. B. mit toUpperCase
- dann können wir die nächste Methode direkt hinten anfügen:
s = "James Bond";
console.log(s.substring(6).toUpperCase()); // BOND
4.6.3 Konstruktoren
Wie Sie gesehen haben, können sich in JavaScript schnell Fehler einschleichen, da Sie bei jedem neuen Objekt die Eigenschaften benennen müssen.
Ein Konstruktor ist eine Funktion, die die Herstellung eines Objekts für Sie übernimmt und somit eine falsche Benennung der Eigenschaften verhindert.
Schauen wir uns nochmal folgendes Objekt an:
let a1 = {
firma: "VW",
modell: "Golf",
kilometerstand: 11032,
fahre: function() {
console.log("brumm brumm");
}
}
Wir bauen uns jetzt einen Konstruktor Auto
, wo wir genau diese drei Eigenschaften und die eine Methode definieren. Der Konstruktor erwartet drei Parameter für die Initialwerte der drei Eigenschaften:
function Auto(firma, modell, km) {
this.firma = firma;
this.modell = modell;
this.kilometerstand = km;
this.fahre = function() {
console.log(this.modell + ": brumm brumm");
}
}
Beachten Sie, dass man innerhalb der Methoden auf die Eigenschaften über this
zugreifen kann.
Ähnlich wie in Java verwenden wir den Konstruktor mit dem Schlüsselwort new
:
let a2 = new Auto('Skoda', 'Octavia', 10320);
Wir überprüfen den Erfolg des Konstruktoraufrufs mit
console.log(a2);
und sehen die Ausgabe:
Auto { firma: 'Skoda', modell: 'Octavia', kilometerstand: 10320, fahre: [Function] }
Der Aufruf der Methode per Punktnotation:
a2.fahre(); // Octavia: brumm brumm
Wenn wir jetzt ein zweites Objekt herstellen, können wir sicher sein, dass die Eigenschaften genauso heißen wie beim ersten Objekt und dass die Funktion "fahre" gleich definiert ist.
let a3 = new Auto('VW', 'Polo', 98001);
a3.fahre(); // Polo: brumm brumm
Wenn man Konstruktoren benutzt, hat man fast schon sowas wie Klassen...
4.7 Code-Analyse
4.7.1 JSHint
JSHint ist ein Softwaretool zum Entdecken von Code-Schwächen und -Fehlern. Man kann das Tool runterladen und auf dem eigenen Rechner installieren, es gibt aber auch eine Webversion, wo Sie direkt im Browser Code per Cut-n-Paste eingeben und checken lassen können:
Hier sehen Sie eine beispielhafte Code-Eingabe in der Webversion:
In einem anderen Teil des Fensters sehen Sie Meldungen/Warnungen, die sich auf die angegebenen Zeilen beziehen:
JSHint prüft den Code, ohne ihn wirklich laufen zu lassen. Es kann daher keine Fehler entdecken, die erst zur Laufzeit entstehen würden. Man nennt dies daher statische Code-Analyse.
Im Gegensatz dazu gibt es auch Mechanismen, die den Code zur Laufzeit testen. Diese nennt man auch Dynamische Software-Testverfahren. Die wichtigsten dynamischen Verfahren sind Unittests oder Intergrationstests.
4.7.2 ESLint
ESLint funktioniert wie JSHint mit einer statischen Code-Analyse. Sie können das Tool als "Extension" in VS Code installieren:
Damit ESLint funktioniert, muss Ihr Projekt als sogenanntes Node-Projekt vorliegen (wie das geht lernen wir in Kapitel 8) und ESLint konfiguriert sein. Eine Anleitung dazu finden Sie auf der Seite von ESLint:
Anschließend zeigt ESLint Ihnen Tipps und Verbesserungsvorschläge direkt in den jeweiligen Codezeilen an. Sie können die Verbesserungsvorschläge dann auch automatisch übernehmen lassen.
Wenn Sie in Zukunft beispielsweise mit verschiedenen Frameworks wie VueJS experimentieren, können Sie ESLint direkt in der Konfiguration des Projekts auswählen.
4.8 Übungen
4.8.1 Fingerübungen
Funktion
Schreiben Sie eine Funktion durchschnitt
, die beliebig viele Zahlen als Parameter bekommen kann (siehe Abschnitt "Variable Parameterzahl") und den Durchschnitt berechnet.
Testen Sie Ihre Funktion mit:
console.log(durchschnitt(10, 20, 30));
console.log(durchschnitt(1, 10));
console.log(durchschnitt(5));
Sie sollten sehen:
20 5.5 5
Array befüllen
Erstellen Sie einen neuen Arrays namens a
und befüllen Sie ihn mit ganzen Zahlen von 0 bis 9. Testen Sie mit
console.log(a);
Sie sollten sehen:
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
String zerlegen und ausgeben mit forEach
Gegeben sei ein String:
s = "Larry;Harry;Mary;Derry";
Zerlegen Sie den String in die vier Namen und geben Sie die Namen einzeln auf der Konsole aus. Verwenden Sie im ersten Schritt eine Schleife und probieren Sie anschließend, das gleiche mit forEach
zu realisieren.
Tipp: Verwenden Sie split
.
Sie sollten sehen:
Larry Harry Mary Derry
Array filtern mit forEach
Gegeben sei ein Array mit Zahlen:
a = [ 1, 5, -3, 0, -10, 11 ];
Erstellen und befüllen Sie einen neuen Array b
, der alle negativen Zahlen aus a
enthält. Verwenden Sie forEach
.
4.8.2 Arrays
Für die folgenden Übungen sollte man auch Funktionen beherrschen.
(A1) Sortierung prüfen
Schreiben Sie eine Funktion is_sorted
, die prüft, ob ein Array sortiert ist (wir betrachten nur Zahlen) und dem entsprechend true oder false zurückgibt.
Testen Sie Ihre Funktion mit
let a = [ 1, 2, 3, 4, 0 ];
let b = [ 10, 100, 1000 ];
let c = [ 3, 2, 1 ];
console.log(is_sorted(a));
console.log(is_sorted(b));
console.log(is_sorted(c));
Sie sollten sehen:
false true false
(A2) Strings einsammeln
Schreiben Sie eine Funktion collect_strings
, die aus einem beliebigen Array (mit gemischten Inhalten) nur die Strings einsammelt und diese als neuen Array zurückgibt.
Testen Sie Ihre Funktion mit:
let test = [ 5, "Harry", 99, "Sally", 501, 33, "Betty" ];
console.log(collect_strings(test));
Sie sollten sehen:
[ 'Harry', 'Sally', 'Betty' ]
(A3) Filtern
Schreiben Sie die Funktion find
, die zwei Parameter bekommt: einen assoziativen Array mit Produkten und eine Zahl (maximaler Preis). Ein Produktarray besteht aus jeweils Produktbezeichnung als Schlüssel und dem Preis als Wert. Als Beispiel nehmen Sie:
let products = { 'iPhone XI': 1200, 'Samsung Universe A100': 2000, 'Pixel 5 XXL': 3000 };
Die Funktion sollte alle Produkte auf der Konsole ausgeben, die günstiger sind als die übergebene Zahl.
Testen Sie mit
find(products, 2100);
Sie sollten sehen:
iPhone XI kostet 1200 EUR Samsung Universe A100 kostet 2000 EUR
4.8.3 Objekte
(O1) Person finden
Jetzt beschäftigen wir uns mit einem assoziativen Array, wo Personen und ihr Alter gespeichert sind:
let data = { "Sam": 33, "Louisa": 63, "Mike": 51, "Lisa": 28, "Conrad": 19, "Lara": 22 };
Schreiben Sie eine Funktion find_closest
mit zwei Parametern, einem (assoziativen) Array und einer Zahl. Die Funktion findet die Person, die altersmäßig am nächsten an der Zahl dran ist und gibt ein neues Objekt mit den Daten der Person (Name, Alter) zurück.
Zum Beispiel sollte der folgende Aufruf
console.log(find_closest(data, 21));
dieses Objekt zeigen:
{ name: 'Lara', age: 22 }
(Wenn es mehrere Personen gibt, die in Frage kommen, kann irgendeine der Möglichkeiten zurückgegeben werden.)
Hinweis: Die Funktion Math.abs
liefert den Betrag einer Zahl zurück, was hilfreich bei Differenzen ist.
(O3) Personenobjekte und forEach
Schreiben Sie einen Konstruktor Person
mit folgenden Eigenschaften:
- vorname
- nachname
- weiblich (boolean)
- alter
Erzeugen Sie einen Array a
, den Sie mit vier Objekten füllen:
- "Jim", "Smith", false, 23
- "Jill", "Stein", true, 16
- "Henry", "Fonda", false, 13
- "Donna", "Leon", true, 63
Durchlaufen Sie den Array mit Hilfe von forEach
, so dass folgende Begrüßungen ausgegeben werden:
Guten Tag, Herr Smith Hallo, Jill Hallo, Henry Guten Tag, Frau Leon
Alle Personen, die älter als 18 sind, sollen mit "Guten Tag" begrüßt werden.