JavaScript - Marijn Haverbeke - E-Book

JavaScript E-Book

Marijn Haverbeke

0,0

Beschreibung

Lernen Sie JavaScript - umfassender Schritt-für-Schritt-Einstieg in die Programmierung und in JavaScript - direkt losprogrammieren mit viele Beispielen und Übungsprojekten - ansteigender Schwierigkeitsgrad bis zu komplexeren Webanwendungen JavaScript ist das Herzstück fast jeder modernen Webanwendung, von Social Apps wie Twitter bis hin zu browserbasierten Spiele-Frameworks. Obwohl es JavaScript auch Anfängern einfach macht, zu programmieren, ist die Sprache trotzdem flexibel und mächtig genug, um mit ihr umfangreiche und komplexe Anwendungen erstellen zu können. Haverbeke zeigt Ihnen die Details und die Tiefen von JavaScript-Code. Umfangreiche Beispiele, Übungen und Projekte wie ein Browserspiel, eine einfache Programmiersprache und ein Malprogramm geben Ihnen praktisches Wissen zum Schreiben Ihrer eigenen Programme an die Hand. Zuerst lernen Sie die Grundstruktur von JavaScript kennen, Sie arbeiten mit Funktionen und Datenstrukturen. Dann erfahren Sie mehr über Fehlerbehandlung und -behebung, Modularität und asynchrone Programmierung bevor Sie mit der Programmierung für Webbrowser fortfahren. - Organisieren Sie Ihren Code mit objektorientierten Methoden und Techniken der funktionalen Programmierung - Skripten Sie für den Browser und erstellen Sie eine einfache Webanwendungen - Nutzen Sie das DOM effektiv, um mit dem Browser zu interagieren - Nutzen Sie Node.js, um Server und Programme zu erstellen. Die zweite Ausgabe von "Die Kunst der JavaScript-Programmierung" taucht tief in die Sprache JavaScript ein, um Ihnen zu zeigen, wie Sie schönen, effektiven Code schreiben können. Die Aktualisierungen umfassen brandneues Material zu Features wie Klassennotationen, Pfeilfunktionen, Iteratoren, Asynchronisationsfunktionen, Template Strings und Blockscope. Ist es nicht endlich an der Zeit, dass Sie die Sprache des Webs fließend beherrschen?

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern

Seitenzahl: 642

Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:

Android
iOS



Marijn Haverbeke ist ein begeisterter polyglotter Programmierer. Er hat an einer breiten Palette von Softwaresystemen gearbeitet, von Datenbanken über Compiler bis hin zu Editoren. Außerdem führt er ein kleines Unternehmen rund um seine Open-Source-Projekte.

Zu diesem Buch – sowie zu vielen weiteren dpunkt.büchern – können Sie auch das entsprechende E-Book im PDF-Format herunterladen. Werden Sie dazu einfach Mitglied bei dpunkt.plus+:

www.dpunkt.plus

Marijn Haverbeke

JavaScript

Richtig gut programmieren lernen –Von der ersten Codezeile bis zum eigenen Projekt

Marijn Haverbeke

Lektorat: Melanie Feldmann

Übersetzung & Satz: G&U Language & Publishing Services GmbH, Flensburg, www.GundU.com

Copy-Editing: Alexander Reischert, www.aluan.de

Herstellung: Stefanie Weidner

Umschlaggestaltung: Helmut Kraus, www.exclam.de

Bibliografische Information der Deutschen Nationalbibliothek

Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.

ISBN:

 

Print

978-3-86490-728-9

PDF

978-3-96088-911-3

ePub

978-3-96088-912-0

mobi

978-3-96088-913-7

1. Auflage 2020

Translation Copyright für die deutschsprachige Ausgabe © 2020 dpunkt.verlag GmbH

Wieblinger Weg 17

69123 Heidelberg

Copyright © 2019 by Marijn Haverbeke. Title of English-language original: Eloquent JavaScript, 3rd Edition: A Modern Introduction to Programming, ISBN 978-1-59327-950-9, published by No Starch Press. German-language edition copyright © 2020 by dpunkt.verlag GmbH. All rights reserved.

Hinweis:

Dieses Buch wurde auf PEFC-zertifiziertem Papier aus nachhaltiger Waldwirtschaft gedruckt. Der Umwelt zuliebe verzichten wir zusätzlich auf die Einschweißfolie.

Schreiben Sie uns:

Falls Sie Anregungen, Wünsche und Kommentare haben, lassen Sie es uns wissen: [email protected]

Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.

Es wird darauf hingewiesen, dass die im Buch verwendeten Soft- und Hardware-Bezeichnungen sowie Markennamen und Produktbezeichnungen der jeweiligen Firmen im Allgemeinen warenzeichen-, marken- oder patentrechtlichem Schutz unterliegen.

Alle Angaben und Programme in diesem Buch wurden mit größter Sorgfalt kontrolliert. Weder Autor noch Verlag noch Übersetzer können jedoch für Schäden haftbar gemacht werden, die in Zusammenhang mit der Verwendung dieses Buches stehen.

5 4 3 2 1 0

Inhaltsübersicht

Einleitung

Teil IDie Sprache

Kapitel 1Werte, Typen und Operatoren

Kapitel 2Programmstruktur

Kapitel 3Funktionen

Kapitel 4Datenstrukturen: Objekte und Arrays

Kapitel 5Funktionen höherer Ordnung

Kapitel 6Das geheime Leben der Objekte

Kapitel 7Projekt: Ein Roboter

Kapitel 8Bugs und Fehler

Kapitel 9Reguläre Ausdrücke

Kapitel 10Module

Kapitel 11Asynchrone Programmierung

Kapitel 12Projekt: Eine Programmiersprache

Teil IIDer Browser

Kapitel 13JavaScript im Browser

Kapitel 14DOM (Document Object Model)

Kapitel 15Umgang mit Ereignissen

Kapitel 16Projekt: Ein Jump’n’Run-Spiel

Kapitel 17Zeichnen auf Leinwand

Kapitel 18HTTP und Formulare

Kapitel 19Projekt: Editor für Pixelgrafiken

Teil IIINode.js

Kapitel 20Einführung in Node.js

Kapitel 21Projekt: Eine Website zur Wissensvermittlung

Kapitel 22Leistung

Hinweise zu den Übungen

Stichwortverzeichnis

Inhaltsverzeichnis

Einleitung

Teil IDie Sprache

1Werte, Typen und Operatoren

1.1Werte

1.2Zahlen

1.3Strings

1.4Unäre Operatoren

1.5Boolesche Werte

1.6Leere Werte

1.7Automatische Typumwandlung

1.8Zusammenfassung

2Programmstruktur

2.1Ausdrücke und Anweisungen

2.2Bindungen

2.3Namen von Bindungen

2.4Die Umgebung

2.5Funktionen

2.6Die Funktion console.log

2.7Rückgabewerte

2.8Ablaufsteuerung

2.9Bedingte Ausführung

2.10While- und do-Schleifen

2.11Einrückungen

2.12for-Schleifen

2.13Eine Schleife abbrechen

2.14Kurzschreibweisen für die Aktualisierung von Bindungen

2.15Werte mithilfe von switch auswählen

2.16Groß- und Kleinschreibung

2.17Kommentare

2.18Zusammenfassung

2.19Übungsaufgaben

3Funktionen

3.1Funktionen definieren

3.2Gültigkeitsbereiche von Bindungen

3.3Funktionen als Werte

3.4Schreibweise von Deklarationen

3.5Pfeilfunktionen

3.6Der Aufrufstack

3.7Optionale Argumente

3.8Closures

3.9Rekursion

3.10Funktionen einführen

3.11Seiteneffekte

3.12Zusammenfassung

3.13Übungen

4Datenstrukturen: Objekte und Arrays

4.1Das Wereichhörnchen

4.2Datenmengen

4.3Eigenschaften

4.4Methoden

4.5Objekte

4.6Veränderbarkeit

4.7Das Tagebuch des Wereichhörnchens

4.8Korrelationen berechnen

4.9Array-Schleifen

4.10Die endgültige Analyse

4.11Arrayologie für Fortgeschrittene

4.12Eigenschaften von Strings

4.13Restparameter

4.14Das Objekt Math

4.15Zerlegung

4.16JSON

4.17Zusammenfassung

4.18Übungen

5Funktionen höherer Ordnung

5.1Abstraktion

5.2Wiederholungen abstrahieren

5.3Funktionen höherer Ordnung

5.4Die Schriftbeispieldaten

5.5Arrays filtern

5.6Transformationen mit map

5.7Zusammenfassungen mit reduce

5.8Komponierbarkeit

5.9Strings und Zeichencodes

5.10Text erkennen

5.11Zusammenfassung

5.12Übungen

6Das geheime Leben der Objekte

6.1Kapselung

6.2Methoden

6.3Prototypen

6.4Klassen

6.5Klassenschreibweise

6.6Abgeleitete Eigenschaften überschreiben

6.7Maps

6.8Polymorphismus

6.9Symbole

6.10Die Iteratorschnittstelle

6.11Get-, Set- und statische Methoden

6.12Vererbung

6.13Der Operator instanceof

6.14Zusammenfassung

6.15Übungen

7Projekt: Ein Roboter

7.1Meadowfield

7.2Die Aufgabe

7.3Persistente Daten

7.4Simulation

7.5Die Route des Postautos

7.6Routen finden

7.7Übungen

8Bugs und Fehler

8.1Die Rolle der Sprache

8.2Strikter Modus

8.3Typen

8.4Tests

8.5Debugging

8.6Fehlerweiterleitung

8.7Ausnahmen

8.8Aufräumen nach Ausnahmen

8.9Selektives Abfangen von Ausnahmen

8.10Assertions

8.11Zusammenfassung

8.12Übungen

9Reguläre Ausdrücke

9.1Reguläre Ausdrücke erstellen

9.2Auf Übereinstimmungen prüfen

9.3Mengen von Zeichen

9.4Teile eines Musters wiederholen

9.5Teilausdrücke gruppieren

9.6Übereinstimmungen und Gruppen

9.7Die Klasse Date

9.8Wort- und String-Grenzen

9.9Alternative Muster

9.10Der Vergleichsmechanismus

9.11Rückverfolgung

9.12Die Methode replace

9.13Gierige Operatoren

9.14RegExp-Objekte dynamisch erstellen

9.15Die Methode search

9.16Die Eigenschaft lastIndex

9.17Eine INI-Datei analysieren

9.18Internationale Zeichen

9.19Zusammenfassung

9.20Übungen

10Module

10.1Module als Bausteine

10.2Pakete

10.3Module

10.4Daten als Code auswerten

10.5CommonJS

10.6ECMAScript-Module

10.7Compiler, Bundler und Minifier

10.8Moduldesign

10.9Zusammenfassung

10.10Übungen

11Asynchrone Programmierung

11.1Asynchronität

11.2Crow Tech

11.3Callbacks

11.4Promises

11.5Fehlschläge

11.6Netzwerke sind schwierig

11.7Kombinationen von Promises

11.8Flooding

11.9Nachrichtenrouting

11.10Async-Funktionen

11.11Generatoren

11.12Die Ereignisschleife

11.13Asynchronitätsbugs

11.14Zusammenfassung

11.15Übungen

12Projekt: Eine Programmiersprache

12.1Der Parser

12.2Der Evaluierer

12.3Sonderformen

12.4Die Umgebung

12.5Funktionen

12.6Kompilierung

12.7Schummeln

12.8Übungen

Teil IIDer Browser

13JavaScript im Browser

13.1Netzwerke und das Internet

13.2Das Web

13.3HTML

13.4HTML und JavaScript

13.5Ausführung in einer Sandbox

13.6Die Browserkriege und das Problem der Kompatibilität

14DOM (Document Object Model)

14.1Die Dokumentstruktur

14.2Bäume

14.3Der Standard

14.4Den Baum durchlaufen

14.5Elemente finden

14.6Das Dokument ändern

14.7Knoten erstellen

14.8Attribute

14.9Layout

14.10Formatierung

14.11CSS

14.12Abfrageselektoren

14.13Positionierung und Animation

14.14Zusammenfassung

14.15Übungen

15Umgang mit Ereignissen

15.1Ereignis-Handler

15.2Ereignisse und DOM-Knoten

15.3Ereignisobjekte

15.4Weiterleitung

15.5Standardaktionen

15.6Tastaturereignisse

15.7Zeigeereignisse

15.8Scrollereignisse

15.9Fokusereignisse

15.10Ladeereignisse

15.11Ereignisse und die Ereignisschleife

15.12Timer

15.13Entprellen

15.14Zusammenfassung

15.15Übungen

16Projekt: Ein Jump’n’Run-Spiel

16.1Das Spiel

16.2Die Technologie

16.3Levels

16.4Ein Level lesen

16.5Akteure

16.6Kapselung als zusätzliche Belastung

16.7Zeichnen

16.8Bewegungen und Kollisionen

16.9Akteure aktualisieren

16.10Tastenbetätigungen verfolgen

16.11Das Spiel ausführen

16.12Übungen

17Zeichnen auf Leinwand

17.1SVG

17.2Das Canvas-Element

17.3Linien und Flächen

17.4Pfade

17.5Kurven

17.6Ein Tortendiagramm zeichnen

17.7Text

17.8Bilder

17.9Transformationen

17.10Transformationen speichern und löschen

17.11Zurück zu unserem Spiel

17.12Auswahl einer Grafikschnittstelle

17.13Zusammenfassung

17.14Übungen

18HTTP und Formulare

18.1Das Protokoll

18.2Browser und HTTP

18.3Fetch

18.4HTTP-Sandboxing

18.5Die Möglichkeiten von HTTP nutzen

18.6Sicherheit durch HTTPS

18.7Formularfelder

18.8Fokus

18.9Deaktivierte Felder

18.10Das Formular als Ganzes

18.11Textfelder

18.12Kontrollkästchen und Optionsschalter

18.13Auswahlfelder

18.14Dateifelder

18.15Clientseitige Datenspeicherung

18.16Zusammenfassung

18.17Übungen

19Projekt: Editor für Pixelgrafiken

19.1Komponenten

19.2Der Status

19.3Aufbau des DOM

19.4Die Leinwand

19.5Die Anwendung

19.6Zeichenwerkzeuge

19.7Speichern und Laden

19.8Der Undo-Verlauf

19.9Die Anwendung einrichten

19.10Warum ist das so schwer?

19.11Übungen

Teil IIINode.js

20Einführung in Node.js

20.1Hintergrund

20.2Der Befehl node

20.3Module

20.4Installation mit NPM

20.5Das Dateisystemmodul

20.6Das HTTP-Modul

20.7Streams

20.8Ein Dateiserver

20.9Zusammenfassung

20.10Übungen

21Projekt: Eine Website zur Wissensvermittlung

21.1Design

21.2Long Polling

21.3Die HTTP-Schnittstelle

21.4Der Server

21.5Der Client

21.6Übungen

22Leistung

22.1Stufenweise Kompilierung

22.2Graphzeichnen

22.3Definition eines Graphen

22.4Kräftebasiertes Graphzeichnen

22.5Arbeit vermeiden

22.6Profiling

22.7Inline-Ersetzung

22.8Weniger überflüssige Objekte erzeugen

22.9Garbage Collection

22.10Dynamische Typen

22.11Zusammenfassung

22.12Übungen

Hinweise zu den Übungen

Stichwortverzeichnis

Für Lotte und Jan

»Wir glauben, dass wir das System zu unserem eigenen Nutzen erstellen. Wir glauben, dass wir es nach unserem eigenen Bilde erschaffen. […] Aber der Computer ist nicht wie wir. Er ist eine Projektion eines sehr kleinen Teils von uns: des Teils, der Logik, Ordnung, Regeln und Klarheit zugetan ist.«

– Ellen Ullman, Close to the Machine: Technophilia and its Discontents (auf Deutsch erschienen als Close to the Machine: Mein Leben mit dem Computer)

Einleitung

In diesem Buch geht es darum, Computern Anweisungen zu geben. Computer sind heutzutage so alltäglich geworden wie Schraubenzieher, allerdings deutlich komplizierter. Deshalb ist es nicht immer einfach, sie auch wirklich das tun zu lassen, was man will.

Wenn Sie Ihren Computer für eine übliche und klar umrissene Aufgabe einsetzen möchten, z.B. um E-Mails anzuzeigen oder Berechnungen wie mit einem Taschenrechner durchzuführen, können Sie einfach die entsprechende Anwendung öffnen und loslegen. Für besondere Aufgaben gibt es dagegen möglicherweise noch keine Anwendung.

An dieser Stelle kommt die Programmierung ins Spiel. Dabei handelt es sich um den Vorgang, ein Programm zu erstellen, also eine Folge genauer Anweisungen, die dem Computer sagen, was er tun soll. Da Computer stumpfsinning und pedantisch sind, ist Programmierung im Grunde zunächst mühselig und frustrierend.

Wenn Sie jedoch darüber hinwegkommen und vielleicht sogar Freude an einer Denkweise in strengen Bahnen finden, die auch eine stumpfe Maschine versteht, kann Programmierung lohnenswert sein. Denn damit lassen sich in Sekunden Dinge erledigen, die sonst ewig dauern würden. Sie bietet eine Möglichkeit, Ihr Werkzeug, den Computer, Aufgaben ausführen zu lassen, die er zuvor nicht beherrschte. Und außerdem ist es eine hervorragende Übung für abstraktes Denken.

Programmierung erfolgt mithilfe einer Programmiersprache. Dabei handelt es sich um eine künstliche Sprache, die dazu dient, Computern Anweisungen zu erteilen. Es ist schon bemerkenswert, dass sich die effektivste Möglichkeit zur Kommunikation mit Computern, die wir erfunden haben, so stark an die Art und Weise anlehnt, wie wir miteinander kommunizieren. Ebenso wie in menschlichen Sprachen können auch in Computersprachen Wörter und Ausdrücke kombiniert werden, um Ideen auszudrücken.

Textschnittstellen wie die BASIC- und DOS-Eingabeaufforderungen der 80er und 90er bildeten einst die Hauptmethode für die Kommunikation mit Computern. Mittlerweile wurden sie größtenteils durch grafische Schnittstellen ersetzt, die leichter zu erlernen sind, aber weniger Freiheiten bieten. Die Computersprachen jedoch sind immer noch vorhanden. Sie müssen nur wissen, wo Sie danach zu suchen haben. Eine dieser Sprachen, nämlich JavaScript, ist in jeden modernen Webbrowser eingebaut und steht daher auf fast jedem Gerät zur Verfügung.

Dieses Buch soll Ihnen helfen, sich so weit mit dieser Sprache vertraut zu machen, dass Sie sie für nützliche und unterhaltsame Zwecke einsetzen können.

Programmierung

Neben JavaScript werde ich auch die Grundlagen der Programmierung erklären. Programmieren ist schwer. Die Grundregeln sind zwar einfach und deutlich, aber die nach diesen Regeln aufgebauten Programme geraten gewöhnlich so vielschichtig, dass sie ihre eigenen Regeln und eine eigene Komplexität aufweisen. In gewissem Sinne bauen Sie ein Labyrinth, in dem Sie sich selbst auch verirren können.

Bei der Lektüre dieses Buches werden Sie sich hin und wieder furchtbar frustriert fühlen. Wenn Programmierung ganz neu für Sie ist, gibt es viel Stoff zu verdauen. Eine Menge dieses Stoffs wird dann auf eine Weise miteinander kombiniert, die es erfordert, zusätzliche Verbindungen herzustellen.

Dazu müssen Sie sich anstrengen. Wenn Sie Schwierigkeiten haben, dem Text zu folgen, dann gehen Sie nicht vorschnell mit sich selbst ins Gericht. Mit Ihnen ist alles in Ordnung – Sie dürfen nur nicht aufgeben! Legen Sie eine Pause ein, lesen Sie etwas erneut und achten Sie darauf, die Beispielprogramme und Übungen nachzuvollziehen und zu begreifen. Lernen ist harte Arbeit. Aber alles, was Sie lernen, gehört zu Ihnen und macht das weitere Lernen einfacher.

»Wenn Aktionen unrentabel werden, sammeln Sie Informationen; wenn Informationen unrentabel werden, legen Sie sich schlafen.«

– Ursula K. LeGuin, The Left Hand of Darknes (auf Deutsch erschienen als Winterplanet und als Die linke Hand der Dunkelheit)

Ein Programm ist vieles zugleich: ein von einem Programmierer geschriebener Text; ein Datenpaket im Arbeitsspeicher des Computers, wo es Aktionen desselben steuert – und damit die lenkende Kraft, die dafür sorgt, dass der Computer das macht, was er tut. Alle Analogien, die Programme mit vertrauten Objekten des Alltags vergleichen, greifen zu kurz. Ein oberflächlicher Vergleich ist der mit einer Maschine: Viele einzelne Teile arbeiten zusammen, damit das Ganze läuft, und wir müssen Möglichkeiten finden, um diese Teile zu verzahnen, damit sie ihren Beitrag zum Funktionieren der Gesamtheit leisten können.

Ein Computer ist eine physische Maschine, die als Wirt solcher immateriellen Maschinen dient. Für sich allein genommen können Computer lediglich ganz einfache Dinge tun. Sie sind nur deshalb so nützlich, weil sie das mit unglaublich hoher Geschwindigkeit erledigen. Ein Programm kann nun auf raffinierte Art und Weise enorme Mengen solcher einfachen Aktionen kombinieren, um so äußerst komplizierte Aufgaben zu erfüllen.

Ein Programm ist ein Gedankenkonstrukt. Seine Erstellung kostet nichts, es ist gewichtslos und wächst rasch, während Sie die Tastatur bearbeiten. Wenn Sie nicht aufpassen, können Größe und Komplexität eines Programms rasch unkontrolliert zunehmen, sodass schließlich selbst die Person, die es geschrieben hat, den Überblick verliert und es nicht mehr richtig versteht. Das größte Herausforderung der Programmierung besteht darin, die Programme unter Kontrolle zu halten. Wenn ein Programm funktioniert, ist es schön. Die Kunst der Programmierung ist die Fähigkeit, die Komplexität im Zaum zu halten. Großartige Programme sind schlicht – also in all ihrer Komplexität möglichst einfach gestaltet.

Manche Programmierer sind der Meinung, dass sie dieser Komplexität am besten Herr werden, indem sie nur einige wenige, gut verstandene Techniken für ihre Programme verwenden. Dazu haben sie strenge Regeln (»empfohlene Vorgehensweisen«, auch »Best Practices«) aufgestellt, die vorschreiben, welche Form Programme haben sollen, und achten sorgfältig darauf, nicht aus dieser eng begrenzten Sicherheitszone auszubrechen.

Das ist jedoch nicht nur langweilig, sondern auch ineffektiv. Neue Probleme erfordern oft neue Lösungen. Programmierung ist eine junge Disziplin, die sich immer noch rasant weiterentwickelt, und sie ist vielgestaltig genug, um Platz für sehr unterschiedliche Vorgehensweisen zu bieten. Es gibt viele furchtbare Fehler, die einem bei der Programmgestaltung unterlaufen können. Sie sollten diese Fehler ruhig machen, damit Sie sie verstehen. Ein Gespür dafür, wie ein gutes Programm auszusehen hat, entwickeln Sie durch praktische Anwendung. Aus einem Satz von Regeln lernen Sie das nicht.

Warum es auf die Sprache ankommt

In den Anfangstagen der Computer gab es noch keine Programmiersprachen. Programme sahen damals wie folgt aus:

00110001 00000000 00000000

00110001 00000001 00000001

00110011 00000001 00000010

01010001 00001011 00000010

00100010 00000010 00001000

01000011 00000001 00000000

01000001 00000001 00000001

00010000 00000010 00000000

01100010 00000000 00000000

Allerdings verlieh die manuelle Eingabe dieser obskuren Muster aus Bits (Nullen und Einsen) den Programmierern das tiefe Gefühl, mächtige Zauberer zu sein. Das war schon viel wert, was die Zufriedenheit am Arbeitsplatz anging.

Jede Zeile des vorigen Programms bildet eine einzige Anweisung. Ins Deutsche übersetzt sehen diese Anweisungen wie folgt aus:

Speichere die Zahl 0 am Speicherort 0.

Speichere die Zahl 1 am Speicherort 1.

Speichere den Wert von Speicherort 1 im Speicherort 2.

Subtrahiere die Zahl 11 von dem Wert im Speicherort 2.

Wenn der Wert in Speicherort 2 die Zahl 0 ist, fahre mit Anweisung 9 fort.

Addiere den Wert von Speicherort 1 zu Speicherort 0.

Addiere die Zahl 1 zum Wert von Speicherort 1.

Fahre mit Anweisung 3 fort.

Gib den Wert von Speicherort 0 aus.

Das ist zwar schon besser lesbar als die Bit-Suppe, aber immer noch ziemlich unverständlich. Es wird besser, wenn wir für die Anweisungen und Speicherorte Namen statt Zahlen verwenden:

Set "total" to 0.

Set "count" to 1.

[loop]

Set "compare" to "count".

Subtract 11 from "compare".

If "compare" is zero, continue at [end].

Add "count" to "total".

Add 1 to "count".

Continue at [loop].

[end]

Output "total".

Können Sie erkennen, wie das Programm abläuft? Die ersten beiden Zeilen geben zwei Speicherorten ihre Startwerte: total wird verwendet, um nach und nach das Ergebnis der Berechnung aufzubauen, während sich count jeweils merkt, welche Zahl wir uns gerade ansehen. Die Zeilen, in denen compare verwendet wird, sind wahrscheinlich die absonderlichsten. Das Programm prüft hier, ob count gleich 11 ist, um zu entscheiden, ob es die Ausführung beenden kann. Da unser hypothetischer Computer ziemlich primitiv ist, kann er nur prüfen, ob eine Zahl gleich 0 ist, und seine Entscheidung darauf gründen. Daher verwendet er den Speicherort compare, um den Wert von count - 11 zu berechnen, und stellt den Vergleich damit an. Die nächsten beiden Zeilen addieren den Wert von count zu dem Ergebnis und setzen count um 1 herauf, solange dieser Wert noch ungleich 11 ist.

In JavaScript sieht das gleiche Programm wie folgt aus:

Diese Version bietet einige weitere Verbesserungen. Vor allem haben wir es hier nicht mehr nötig, das Programm ausdrücklich anzuweisen, vor- oder zurückzuspringen. Darum kümmert sich das while-Konstrukt. Es setzt die Ausführung des dahinter stehenden Blocks (in geschweiften Klammern) so lange fort, wie die ihm übergebene Bedingung zutrifft. Diese Bedingung lautet count <= 10, was bedeutet: »count ist kleiner oder gleich 10.« Wir müssen hier nicht mehr einen Zwischenwert berechnen und mit 0 vergleichen, was ohnehin ein für das eigentliche Ziel unbedeutender Detailmechanismus war. Programmiersprachen sind unter anderem deshalb so leistungsfähig, weil sie uns solche uninteressanten Einzelheiten abnehmen. Am Ende des Programms, nach dem Abschluss des while-Konstruktors, sorgt die Operation console.log dafür, dass das Resultat ausgegeben wird.

Wenn uns die bequemen Operationen range und sum zur Verfügung stehen, die eine Zahlenmenge aus einem gegebenen Bereich zusammenstellen bzw. die Summe einer Menge von Zahlen berechnen können, sind wir in der Lage, das Programm wie folgt zu schreiben:

console.log(sum(range(1, 10)));

// → 55

Die Moral von der Geschichte ist, dass sich Programme auf verschiedene Weisen ausdrücken lassen – lang und kurz, unverständlich und verständlich. Die erste Version des Programms war extrem obskur, während die letzte schon fast wie Deutsch aussieht: »Protokolliere die Summe des Bereichs der Zahlen von 1 bis 10.« Wie sich Operationen wie sum und range definieren lassen, werden wir uns in den späteren Kapiteln noch ansehen.

Eine gute Programmiersprache unterstützt Programmierer, indem sie ihnen erlaubt, die groben Aktionen, die der Computer durchführen soll, zu beschreiben, und die Details wegzulassen. Sie stellt komfortable Bausteine bereit (wie while und console.log), ermöglicht die Definition eigener Bausteine (wie sum und range) und erleichtert es, diese Bausteine zu kombinieren.

Was ist JavaScript?

JavaScript wurde 1995 als eine Möglichkeit eingeführt, um Webseiten im Netscape Navigator Programme hinzuzufügen. Die Sprache wurde seitdem von allen anderen wichtigen grafischen Browsern übernommen. Sie hat moderne Webanwendungen möglich gemacht, mit denen Sie direkt arbeiten können, ohne nach jeder Aktion auf einen neuen Seitenaufbau warten zu müssen. JavaScript wird auch auf herkömmlichen Webseiten eingesetzt, um verschiedenen Formen der Interaktivität und ausgeklügelte Funktionen zu bieten.

Beachten Sie jedoch, dass JavaScript so gut wie nichts mit der Programmiersprache Java zu tun hat. Der Name wurde eher aus Marketinggründen gewählt. Bei der Einführung von JavaScript wurde Java stark angepriesen und nahm an Beliebtheit zu. Jemand hielt es für eine gute Idee, auf der Erfolgswelle mitzuschwimmen. Bei dem Namen ist es dann geblieben.

Nach der Übernahme in andere Browser als Netscape wurde ein Normdokument verfasst, um zu beschreiben, wie sich JavaScript verhalten soll, damit auch tatsächlich immer die gleiche Sprache gemeint ist, wenn Software behauptet, JavaScript zu unterstützen. Dieser Standard wird nach der Organisation Ecma International, die die Normung vorgenommen hat, als ECMAScript bezeichnet. In der Praxis können die Begriffe ECMAScript und JavaScript synonym verwendet werden – es sind zwei Bezeichnungen für dieselbe Sprache.

Manche Personen werden Ihnen fürchterliche Dinge über JavaScript erzählen. Viele davon sind wahr. Als ich zum ersten Mal etwas in JavaScript schreiben musste, lernte ich die Sprache sehr schnell zu hassen. Sie akzeptierte fast alles, was ich eingab, deutete es dann aber völlig anders, als ich es gemeint hatte. Dies lag zu einem großen Teil natürlich auch daran, dass ich damals keine Ahnung hatte, was ich da eigentlich tat. Aber es ist auch das Symptom eines echten Problems: JavaScript ist absurd freizügig. Dahinter stand die Idee, dass es das Programmieren in JavaScript für Anfänger erleichtern würde. In Wirklichkeit aber erschwert dies, Probleme in Programmen zu finden, da das System Sie nicht darauf hinweist.

Diese Flexibilität hat jedoch auch ihre Vorteile. Sie erlaubt viele Techniken, die in strengeren Sprachen unmöglich sind. Wie Sie noch sehen werden (etwa in Kapitel 10), kann sie auch dazu genutzt werden, einige der Mängel von JavaScript auszubügeln. Nachdem ich die Sprache gründlich gelernt und eine Weile damit gearbeitet hatte, begann ich JavaScript sogar zu mögen.

Es gibt verschiedene Versionen von JavaScript. ECMAScript Version 3 war während des Aufstiegs von JavaScript etwa zwischen 2000 und 2010 sehr weit verbreitet. In dieser Zeit wurde an der anspruchsvolleren Version 4 gearbeitet, bei der es einige radikale Verbesserungen und Erweiterungen geben sollte. Es erwies sich jedoch als politisch schwierig, eine lebendige, weiträumig genutzte Sprache so einschneidend zu verändern, weshalb die Arbeiten an Version 4 im Jahre 2008 eingestellt wurden. Stattdessen wurde 2009 die weniger ambitionierte Version 5 veröffentlicht, die nur einige nichtkontroverse Verbesserungen bot. 2015 kam die stark überarbeitete Version 6 heraus, die einige der für Version 4 geplanten Aspekte enthielt. Seitdem gab es jedes Jahr kleinere Aktualisierungen.

Da sich die Sprache weiterentwickelt, müssen die Browser mithalten. Wenn Sie einen älteren Browser verwenden, kann es sein, dass er nicht alle Funktionen unterstützt. Die Entwickler der Sprache achten sorgfältig darauf, keine Änderungen einzuführen, die bestehende Programme funktionsunfähig machen würden. Daher können neue Browser immer noch ältere Programme ausführen. In diesem Buch verwendete ich die JavaScript-Version von 2017.

Browser sind jedoch nicht die einzigen Plattformen, auf denen JavaScript eingesetzt wird. Auch einige Datenbanken wie MongoDB oder CouchDB nutzen JavaScript als Skripterstellungs- und Abfragesprache. Verschiedene Plattformen für die Desktop- und Serverprogrammierung, insbesondere das Projekt Node.js (um das es in Kapitel 20 geht), bieten eine Umgebung für die JavaScript-Programmierung außerhalb des Browsers.

Die Codebeispiele

Code ist der Text eines Programms. Die meisten Kapitel dieses Buches enthalten eine Menge Code. Ich bin der Meinung, dass das Lesen und Schreiben von Code unverzichtbar ist, um Programmieren zu lernen. Überfliegen Sie die Beispiele nicht einfach, sondern lesen Sie sie aufmerksam, um sie auch wirklich zu verstehen. Das kann zu Anfang langsam und verwirrend sein. Aber ich verspreche Ihnen, dass Sie den Bogen schon bald heraushaben werden. Das Gleiche gilt auch für die Übungen. Sie haben diese erst dann richtig verstanden, wenn Sie eine Lösung dafür geschrieben haben.

Ich empfehle Ihnen, Ihre Lösungen zu den Übungsaufgaben tatsächlich in einem JavaScript-Interpreter auszuprobieren. Dadurch erhalten Sie unmittelbar eine Rückmeldung, ob sie funktionieren, und werden hoffentlich auch dazu animiert, über die Aufgabenstellung hinaus noch weiter zu experimentieren.

Die einfachste Möglichkeit, den Beispielcode in diesem Buch auszuführen und damit zu experimentieren, besteht darin, ihn in der Online-Version des Buchs auf https://eloquentjavascript.net anzusehen. Dort können Sie auf die Codebeispiele klicken, um sie zu bearbeiten, auszuführen und sich die Ausgaben anzusehen. Um die Übungen zu bearbeiten, besuchen Sie https://eloquentjavascript.net/code. Dort erhalten Sie den Ausgangscode für alle Programmierübungen und können auch einen Blick auf die Lösungen werfen.

Wollen Sie die Programme aus diesem Buch außerhalb der Begleitwebseite ausführen, ist etwas Vorsicht geboten. Viele der Beispiele sind eigenständig und sollten in jeder JavaScript-Umgebung funktionieren. Code in den hinteren Kapiteln ist jedoch oft für eine bestimmte Umgebung geschrieben (den Browser oder Node.js) und kann nur dort ausgeführt werden. Außerdem werden in einigen Kapiteln umfangreichere Programme erstellt, deren einzelne Teile voneinander und manchmal auch von externen Dateien abhängen. Die Sandbox auf der Webseite stellt Links zu Zip-Dateien mit allen Skript- und Datendateien bereit, die erforderlich sind, um den Code zu einem Kapitel auszuführen.

Übersicht über dieses Buch

Dieses Buch besteht aus drei Teilen. Die ersten zwölf Kapitel beschreiben die Sprache JavaScript, in den nächsten sieben geht es um Webbrowser und ihre Programmierung mit JavaScript, und die beiden letzten sind Node.js gewidmet, einer weiteren Programmierumgebung für JavaScript.

Über das ganze Buch verstreut sind fünf Projektkapitel, in denen umfangreiche Beispielprogramme beschrieben werden, um Ihnen einen Vorgeschmack auf die tatsächliche Programmierarbeit zu geben. In diesen Kapiteln programmieren wir einen Zustellroboter, eine Programmiersprache, ein Jump’n’Run-Spiel, ein Malprogramm und eine dynamische Webseite.

Der erste Teil des Buches beginnt mit vier Kapiteln, die die Grundstruktur von JavaScript vorstellen. Sie geben eine Einführung in Steuerstrukturen (z. B. das while-Konstrukt, das Sie bereits in dieser Einleitung kennengelernt haben), Funktionen (von Ihnen selbst geschriebene Bausteine) und Datenstrukturen. Damit sind Sie schon in der Lage, einfache Programme zu schreiben. Anschließend werden in den Kapiteln 5 und 6 Techniken eingeführt, um mithilfe von Funktionen und Objekten abstrakteren Code zu schreiben und die Komplexität zu reduzieren.

Nach einem ersten Projektkapitel geht es im ersten Teil des Buches mit Kapiteln über Fehlerbehandlung und -behebung, reguläre Ausdrücke (ein wichtiges Instrument für die Arbeit mit Text), Modularität (eine weitere Maßnahme gegen zu hohe Komplexität) und asynchrone Programmierung (Umgang mit Ereignissen, die einige Zeit dauern) weiter. Das zweite Projektkapitel schließt den ersten Teil ab.

Der zweite Teil – die Kapitel 13 bis 19 – beschreibt die Werkzeuge, auf die JavaScript im Browser Zugriff hat. Sie erfahren hier, wie Sie etwas auf dem Bildschirm darstellen (Kapitel 14 bis 17), wie Sie auf Benutzereingaben reagieren (Kapitel 15) und wie Sie über das Netzwerk kommunizieren (Kapitel 18). Auch in diesem Teil gibt es wieder zwei Projektkapitel.

Im Anschluss daran wird in Kapitel 20 Node.js beschrieben und in Kapitel 21 eine kleine Webseite damit erstellt.

In Kapitel 22 finden Sie schließlich einige Überlegungen dazu, wie Sie JavaScript-Programme optimieren können, um die Ausführung zu beschleunigen.

Schreibweisen

Text in einer nichtproportionalen Schrift kennzeichnet in diesem Buch Programmelemente – sowohl eigenständige Fragmente als auch »Zitate« aus einem in der Nähe abgedruckten Programm. Die Programme selbst (von denen Sie inzwischen ja schon einige gesehen haben) werden wie folgt dargestellt:

Um die erwartete Ausgabe eines Programms zu zeigen, wird sie manchmal hinter zwei Schrägstrichen und einem Pfeil angegeben:

console.log(factorial(8));

// → 40320

Viel Glück!

Teil I

Die Sprache

»Unter der Oberfläche der Maschine bewegt sich das Programm. Mühelos dehnt es sich aus und zieht sich zusammen. In großer Harmonie zerstreuen sich Elektronen und kommen wieder zusammen. Die Formen auf dem Monitor sind nur Wellen auf dem Wasser. Das Wesentliche bleibt unsichtbar darunter.«

– Meister Yuan-Ma, The Book of Programming

1Werte, Typen und Operatoren

In der Welt der Computer gibt es nichts anderes als Daten. Daten können gelesen, geändert und neu erstellt werden, aber es ist nicht möglich, Dinge, die keine Daten sind, auch nur zu erwähnen. Alle diese Daten werden als lange Folgen von Bits gespeichert und sind einander dadurch grundsätzlich ähnlich.

Bits sind alle Dinge, die zwei Werte annehmen können, wobei diese Werte gewöhnlich als 0 und 1 dargestellt werden. Innerhalb des Computers nehmen sie die Form einer hohen oder niedrigen elektrischen Ladung, eines starken oder schwachen Signals bzw. eines hellen oder dunklen Punkts auf einer CD an. Jede diskrete Information kann auf eine Folge von Nullen und Einsen reduziert und damit durch Bits dargestellt werden.

Beispielsweise können wir eine Zahl wie 13 durch Bits ausdrücken. Das funktioniert genauso wie bei Dezimalzahlen, allerdings verwenden wir dazu nur zwei statt zehn verschiedene Ziffern und der Betrag wächst von rechts nach links mit jeder Stelle um den Faktor 2. Die folgende Darstellung zeigt die Bits, die die Zahl 13 bilden, mit dem Betrag der jeweiligen Stellen darunter:

0  0  0  0 1 1 0 1

128 64 32 16 8 4 2 1

Die Binärzahl lautet also 00001101. Die von 0 verschiedenen Stellen stehen darin für die Beträge 8, 4, und 1, deren Addition 13 ergibt.

1.1Werte

Stellen Sie sich ein Meer von Bits vor. Der flüchtige Datenspeicher (Arbeitsspeicher) eines typischen modernen Computers enthält über 30 Milliarden Bits. Im nichtflüchtigen Speicher (also auf der Festplatte oder einer vergleichbaren Einrichtung) sind es gewöhnlich einige Größenordnungen mehr.

Um solche Mengen von Bits handhaben zu können, ohne die Orientierung zu verlieren, müssen wir sie daher in Blöcke aufteilen, die für einzelne Informationen stehen. In einer JavaScript-Umgebung nennen wir diese Blöcke Werte. Obwohl alle Werte aus Bits bestehen, können sie verschiedene Rollen einnehmen, wobei die Rolle eines Werts durch seinen Typ bestimmt wird. Einige Werte sind Zahlen, andere sind Texte, wieder andere Funktionen usw.

Um einen Wert zu erstellen, müssen Sie lediglich seinen Namen angeben. Das ist praktisch, denn dies bedeutet, dass es nicht nötig ist, Material für Werte heranzuschaffen oder gar dafür zu bezahlen. Sie fordern einfach den Wert an und – Simsalabim – da ist er. Natürlich werden die Werte in Wirklichkeit nicht so einfach aus dem Hut gezaubert. Jeder Wert muss irgendwo gespeichert werden, und wenn Sie gleichzeitig eine riesige Menge von Werten verwenden, geht Ihnen irgendwann der Speicher aus. Glücklicherweise ist das jedoch nur dann ein Problem, wenn Sie die Werte wirklich alle gleichzeitig benötigen. Wenn Sie einen Wert nicht brauchen, löst er sich auf und lässt seine Bits zurück, die dann als Baumaterial für die nächste Generation von Werten wiederverwendet werden können.

In diesem Kapitel lernen Sie die kleinsten Elemente von JavaScript-Programmen kennen, nämlich die einfachen Wertetypen und die Operatoren, die diese Werte bearbeiten können.

1.2Zahlen

Werte, die Zahlen darstellen, sind sogenannte numerische Werte. In einem JavaScript-Programm werden sie gewöhnlich wie folgt geschrieben:

13

Wenn Sie das in ein Programm eingeben, wird innerhalb des Computerarbeitsspeichers das Bitmuster für die Zahl 13 gebildet.

Um einen numerischen Wert zu speichern, verwendet JavaScript stets eine feste Anzahl von Bits, nämlich 64. Daraus lässt sich nur eine begrenzte Anzahl von Mustern bilden, was die Menge der darstellbaren Zahlen beschränkt. Mit n Dezimalstellen lassen sich 10n Zahlen ausdrücken, mit 64 Binärstellen 264 Zahlen, also 18 Trillionen (eine 18 mit 18 Nullen). Das ist eine ganze Menge.

Computerarbeitsspeicher waren früher viel kleiner, weshalb zur Darstellung von Zahlen gewöhnlich 8 oder 16 Bits verwendet wurden. Dabei war es leicht möglich, versehentlich einen Überlauf zu verursachen, also eine Zahl zu bekommen, die nicht in die gegebene Anzahl von Bits passt. Heute haben sogar Computer für die Westentasche eine Menge Arbeitsspeicher, sodass es möglich ist, 64-Bit-Blöcke zu verwenden. Um Überläufe muss man sich nur dann Gedanken machen, wenn mit wirklich astronomischen Zahlen gearbeitet wird.

Allerdings passen nicht alle Zahlen kleiner als 18 Trillionen in den numerischen Typ von JavaScript. Da es auch möglich sein muss, negative Zahlen zu speichern, wird ein Bit zur Angabe des Vorzeichens verwendet. Ein noch größeres Problem ist die Darstellung nicht ganzzahliger Werte. Dann müssen einige der Bits dafür genutzt werden, die Position des Kommas festzuhalten. Die größte ganze Zahl, die tatsächlich gespeichert werden kann, liegt daher im Bereich von 9 Billiarden (15 Nullen), was immer noch angenehm groß ist.

Bruchzahlen werden mit einem Punkt (statt Komma) geschrieben:

9.81

Für sehr große und sehr kleine Zahlen kann auch die wissenschaftliche Schreibweise verwendet werden. Dazu schreiben Sie e (für Exponent), gefolgt vom Exponenten:

2.998e8

Berechnungen mit ganzen Zahlen (sogenannten Integer-Zahlen) kleiner als die zuvor genannten 9 Billiarden sind garantiert präzise, Berechnungen mit Bruchzahlen im Allgemeinen jedoch nicht. Ebenso wie es nicht möglich ist, π durch eine endliche Anzahl von Dezimalstellen genau darzustellen, verlieren viele Zahlen etwas von ihrer Präzision, wenn nur 64 Bits zu ihrer Speicherung zur Verfügung sehen. Das ist schade, führt in der Praxis aber nur in besonderen Situationen zu Problemen. Wichtig ist, dass Sie sich dieses Umstands bewusst sind und Bruchzahlen nur als Näherungen und nicht als exakte Werte betrachten.

Berechnungen

Das Wichtigste, was man mit Zahlen anstellt, sind Berechnungen. Arithmetische Operationen wie Addition oder Multiplikation nehmen zwei numerische Werte entgegen und produzieren daraus eine neue Zahl. In JavaScript sieht das wie folgt aus:

100 + 4 * 11

Die Symbole + und * werden Operatoren genannt. Der erste steht für die Addition, der zweite für die Multiplikation. Ein Operator zwischen zwei Werten wird auf diese beiden angewendet und produziert einen neuen Wert.

Aber bedeutet dieses Beispiel »addiere 100 und 4 und multipliziere das Ergebnis mit 11« oder erfolgt die Multiplikation vor der Addition? Wie Sie wahrscheinlich wissen, wird die Multiplikation zuerst ausgeführt. Allerdings können Sie wie in der Mathematik die Reihenfolge ändern, indem Sie die Addition in Klammern setzen:

(100 + 4) * 11

Für die Subtraktion gibt es den Operator - und für die Division den Operator /.

Wenn keine Klammern gesetzt sind, werden Operatoren in der Reihenfolge angewendet, die durch ihren Rang bestimmt ist. In unserem Beispiel erfolgt die Multiplikation vor der Addition. Der Operator / hat den gleichen Rang wie *. Auch + und - haben den gleichen Rang. Folgen Operatoren des gleichen Rangs aufeinander, z. B. in 1 - 2 + 1, werden sie von links nach rechts ausgewertet: (1 - 2) + 1.

Machen Sie sich aber keine Sorgen über die Rangfolge von Operatoren. Im Zweifelsfall fügen Sie einfach Klammern hinzu.

Es gibt noch einen weiteren arithmetischen Operator, den Sie aber möglicherweise nicht sofort erkennen. Das Symbol % wird oft für die Restoperation verwendet. X % Y ist der Rest der Division von X durch Y. Beispielsweise ergibt 314 % 100 den Wert 14 und 144 % 12 den Wert 0. Der Restoperator hat denselben Rang wie Multiplikation und Division. Meistens wird er als Modulo bezeichnet.

Besondere Zahlen

In JavaScript gibt es drei besondere Werte, die zwar als Zahlen angesehen werden, sich aber nicht so verhalten.

Die ersten beiden sind Infinity und -Infinity, die für positive bzw. negative Unendlichkeit stehen. Infinity - 1 ist immer noch Infinity usw. Verlassen Sie sich aber nicht zu sehr auf Berechnungen mit unendlichen Werten. Sie sind mathematisch zweifelhaft und führen schnell zu der dritten besonderen Zahl, nämlich NaN.

NaN steht für »not a number«, also »keine Zahl«, obwohl dieser Wert tatsächlich zu den numerischen Werten gehört. Dieses Ergebnis erhalten Sie beispielsweise, wenn Sie versuchen, 0 / 0 zu berechnen (null dividiert durch null), Infinity - Infinity oder irgendeine andere numerische Operation durchführen, die kein sinnvolles Ergebnis liefert.

1.3Strings

Den nächsten grundlegenden Datentyp bilden die Strings. Sie dienen zur Darstellung von Text. Um sie zu schreiben, wird der Inhalt in Anführungszeichen gesetzt:

`Down on the sea`

"Lie on the ocean"

'Float on the ocean'

Um Strings zu kennzeichnen, können Sie Backticks, doppelte oder einfache Anführungszeichen verwenden. Wichtig ist, dass Sie am Anfang und am Ende des Strings jeweils das gleiche Zeichen setzen.

Zwischen Anführungszeichen können Sie fast alles schreiben. JavaScript macht automatisch einen String-Wert daraus. Allerdings gibt es bei einigen Zeichen Probleme. Sie können sich vorstellen, dass es knifflig wird, wenn Sie versuchen, Anführungszeichen zwischen Anführungszeichen zu setzen. Zeilenumbrüche (also die Zeichen, die Sie erhalten, wenn Sie die Eingabetaste drücken) lassen sich nur dann ohne Maskierung eingeben, wenn der String in Backticks (`) eingeschlossen ist.

Um auch solche problematischen Zeichen in Strings einschließen zu können, wird die folgende Schreibweise verwendet: Tritt innerhalb von Text in Anführungszeichen ein Backslash (umgekehrter Schrägstrich, \) auf, dann bedeutet dies, dass das darauffolgende Zeichen eine besondere Bedeutung hat. Auf diese Weise wird das Zeichen maskiert. Ein Anführungszeichen mit einem vorausgehenden Backslash beendet den String nicht, sondern ist ein Teil von ihm. Steht das Zeichen n hinter einem Backslash, wird es als Zeilenumbruch gedeutet, und ein t hinter einem Backslash steht für den Tabulator. Betrachten Sie als Beispiel den folgenden String:

"This is the first line\nAnd this is the second"

Der enthaltene Text lautet:

This is the first line

And this is the second

Es kann natürlich auch vorkommen, dass ein Backslash in einem String als Backslash wiedergegeben werden soll, anstatt eine besondere Funktion auszuüben. Wenn zwei Backslashes aufeinander folgen, maskiert der erste den zweiten, sodass im resultierenden String-Wert nur der zweite übrigbleibt. Um beispielsweise den String "A newline character is written like "\n"." auszudrücken, können Sie Folgendes schreiben:

"A newline character is written like \"\\n\"."

Um innerhalb eines Computers existieren zu können, müssen auch Strings als Folge von Bits modelliert werden. JavaScript zieht dazu den Unicode-Standard heran. Er weist Zahlen praktisch jedem Zeichen zu, das Sie jemals brauchen könnten, darunter auch griechischen, arabischen, japanischen und armenischen Buchstaben usw. Wenn es für jedes Zeichen eine Zahl gibt, kann ein String als Folge von Zahlen ausgedrückt werden.

Genau das ist es, was JavaScript macht. Es gibt jedoch ein Problem: In der JavaScript-Darstellung werden 16 Bits pro String-Element genutzt, womit sich 216 verschiedene Zeichen beschreiben lassen. Unicode aber definiert noch mehr Zeichen, zurzeit etwa doppelt so viele. Daher nehmen manche Zeichen, etwa Emojis, in JavaScript zwei Zeichenpositionen ein. Auf Strings und Zeichencodes werden wir auf S. 64 zurückkommen.

Strings können nicht dividiert, multipliziert oder subtrahiert werden, aber es ist möglich, den Operator + auf sie anzuwenden. In diesem Fall dient er nicht zur Addition, sondern zur Verkettung – er verbindet die beiden Strings. Die folgende Zeile produziert den String "Verkettung":

"Ver" + "ket" + "t" + "ung"

Es gibt eine Reihe von zugehörigen Funktionen (Methoden), um noch andere Operationen an String-Werten auszuführen. Mehr über Methoden erfahren Sie auf S. 64.

Strings in einfachen oder doppelten Anführungszeichen verhalten sich sehr ähnlich. Der einzige Unterschied besteht darin, welche Art von Anführungszeichen Sie in ihnen maskieren müssen. Strings in Backticks dagegen, die gewöhnlich als Template-Literale bezeichnet werden, leisten noch mehr. Sie können nicht nur mehrere Zeilen überspannen, sondern auch andere Werte enthalten:

`half of 100 is ${100 / 2}`

Wenn Sie in einem Template-Literal etwas in ${} schreiben, wird das Ergebnis berechnet, in einen String umgewandelt und an dieser Stelle eingeführt. In dem Beispiel ergibt sich half of 100 is 50.

1.4Unäre Operatoren

Nicht alle Operatoren sind Symbole. Einige werden auch als Wörter geschrieben. Ein Beispiel dafür ist der Operator typeof. Er erzeugt einen String-Wert mit dem Namen des Typs, den der übergebene Wert hat:

console.log(typeof 4.5)

// → number

console.log(typeof "x")

// → string

In unserem Beispielcode verwenden wir console.log um anzugeben, dass wir das Ergebnis einer Auswertung sehen wollen. Mehr darüber erfahren Sie im nächsten Kapitel.

Alle anderen bisher vorgestellten Operatoren nehmen zwei Werte entgegen, typeof dagegen nur einen. Operatoren, die zwei Werte verwenden, werden als binäre Operatoren bezeichnet, Operatoren mit nur einem Eingangswert als unäre. Der Minusoperator kann sowohl als binärer als auch als unärer Operator eingesetzt werden:

console.log(- (10 - 2))

// → -8

1.5Boolesche Werte

Oft ist es praktisch, einen Wert zur Verfügung zu haben, der nur zwei mögliche Formen annehmen kann, etwa »ja« und »nein« oder »ein« und »aus«. Für diesen Zweck gibt es in JavaScript den booleschen Datentyp mit nur zwei Werten, nämlich »wahr« und »falsch«, geschrieben als true und false.

Vergleiche

Eine Möglichkeit, um boolesche Werte zu erzeugen, sieht wie folgt aus:

console.log(3 > 2)

// → true

console.log(3 < 2)

// → false

Die Zeichen > und < sind die herkömmlichen Symbole für »ist größer als« bzw. »ist kleiner als«. Die Anwendung dieser binären Operatoren ergibt einen booleschen Wert, der anzeigt, ob die Vergleiche wahr sind oder nicht.

Auch Strings lassen sich auf diese Weise vergleichen:

console.log("Aardvark" < "Zoroaster")

// → true

Die Sortierung von Strings ist grob gesehen alphabetisch, allerdings weicht sie von der Reihenfolge ab, wie man sie aus einem Wörterbuch kennt: Großbuchstaben sind immer »kleiner« als Kleinbuchstaben (es gilt also "Z" < "a") und die Sortierung schließt auch Zeichen ein, die keine Buchstaben sind (wie !, - usw.). Beim String-Vergleich geht JavaScript die Zeichen von links nach rechts durch und vergleicht ihre Unicode-Codes einen nach dem anderen.

Es gibt nur einen Wert in JavaScript, der nicht gleich sich selbst ist, und das ist NaN (»not a number«):

NaN kennzeichnet das Ergebnis einer unsinnigen Berechnung und ist daher nicht gleich dem Ergebnis einer anderen unsinnigen Berechnung.

Logische Operatoren

Auf die booleschen Werte selbst können ebenfalls Operationen angewendet werden. Dazu gibt es in JavaScript die drei logischen Operatoren und, oder und nicht. Damit lassen sich Schlussfolgerungen über boolesche Werte anstellen.

Der Operator && steht für das logische und. Es handelt sich bei ihm um einen binären Operator, und das Ergebnis lautet nur dann true, wenn beide gegebenen Werte wahr sind:

console.log(true && false)

// → false

console.log(true && true)

// → true

Der Operator ||, das logische oder, ergibt true, wenn wenigstens einer der beiden gegebenen Werte wahr ist:

console.log(false || true)

// → true

console.log(false || false)

// → false

Nicht wird als Ausrufezeichen geschrieben. Dieser unäre Operator kehrt den gegebenen Wahrheitswert um: !true ergibt false, !false ergibt true.

Der letzte logische Operator, den ich hier besprechen möchte, ist weder unär noch binär, sondern ternär, d. h., er nimmt drei Werte entgegen. Geschrieben wird er wie folgt mit einem Fragezeichen und einem Doppelpunkt:

console.log(true ? 1 : 2);

// → 1

console.log(false ? 1 : 2);

// → 2

Dieser Operator wird als Bedingungsoperator bezeichnet (manchmal auch nur als »der ternäre Operator«, da er der einzige dieser Art in JavaScript ist). Der Wert auf der linken Seite des Fragezeichens bestimmt, welcher der beiden anderen Werte ausgegeben werden soll. Ist er wahr, so wird der mittlere genommen, ist er falsch, der rechte.

1.6Leere Werte

Um die Abwesenheit eines sinnvollen Werts zu kennzeichnen, werden die beiden besonderen Werte null und undefined verwendet. Es handelt sich bei ihnen zwar um Werte, allerdings haben sie keinen Informationsgehalt.

Viele Operationen, die keinen sinnvollen Wert produzieren (einige davon werden Sie später noch kennenlernen), geben undefined zurück, da sie schließlich irgendeinen Wert zurückgeben müssen.

Der Bedeutungsunterschied zwischen undefined und null ist eher ein Missgriff im Design von JavaScript und spielt meistens keine Rolle. Wenn Sie mit diesen Werten zu tun haben, sollten Sie sie als größtenteils austauschbar betrachten.

1.7Automatische Typumwandlung

In der Einleitung habe ich schon erwähnt, dass JavaScript alles versucht, um möglichst jedes Programm zu akzeptieren, das Sie übergeben, auch wenn dieses Programm merkwürdige Dinge tut. Die folgenden Beispielausdrücke machen das schön deutlich:

Wird ein Operator auf einen Wert eines unpassenden Typs angewendet, wandelt JavaScript diesen Wert stillschweigend in den erforderlichen Typ um. Die Regeln dafür entsprechend aber nicht immer dem, was Sie beabsichtigen oder erwarten. Dieser Vorgang wird implizite Typumwandlung genannt. Aus null im ersten Ausdruck wird 0. Der String "5" im zweiten Ausdruck wird in die Zahl 5 umgewandelt. Im dritten Ausdruck dagegen wird erst versucht, + für eine String-Verkettung und nicht für eine Addition zu verwenden, weshalb die Zahl 1 hier in den String "1" umgewandelt wird.

Wenn Werte, die nicht offensichtlich Zahlen entsprechen (wie "five" oder "undefined"), dennoch in Zahlen umgewandelt werden, erhalten Sie den Wert NaN. Arithmetische Operationen mit NaN ergeben immer wieder NaN. Wenn Sie diesen Wert an unerwarteter Stelle erhalten, sollten Sie daher nach versehentlichen Typumwandlungen Ausschau halten.

Ich rate dazu, diese aus drei Zeichen bestehenden Operatoren als Schutzvorkehrung zu nutzen, um unbeabsichtigte Typumwandlungen zu verhindern. Wenn Sie aber sicher sind, dass auf beiden Seiten Werte desselben Typs stehen, können Sie problemlos die kürzeren Operatoren verwenden.

Kurzschließen logischer Operatoren

Die logischen Operatoren && und || handhaben Werte unterschiedlichen Typs auf eigenartige Weise. Sie konvertieren den Wert auf der linken Seite in einen booleschen Typ, um zu entscheiden, was sie tun sollen, aber je nach Operator und dem Ergebnis dieser Umwandlung geben sie entweder den ursprünglichen linken oder den rechten Wert zurück.

Beispielsweise gibt der Operator || den Wert auf der linken Seite zurück, wenn dieser in true umgewandelt werden kann, und sonst den Wert auf der rechten Seite. Bei booleschen Werten führt das zu dem zu erwartenden Ergebnis, und Werte anderer Typen werden in ähnlichem Sinne behandelt:

console.log(null || "user")

// → user

console.log("Agnes" || "user")

// → Agnes

Diese Vorgehensweise können wir als eine Möglichkeit nutzen, um auf einen Standardwert zurückzugreifen. Besteht die Gefahr, dass ein Wert leer ist, können Sie hinter || einen Ersatzwert angeben. Falls der ursprüngliche Wert in false konvertiert wird, erhalten Sie dann den Ersatzwert. Nach den Regeln für die Umwandlung von Strings und Zahlen in boolesche Werte werden 0, NaN und der leere String ("") als false aufgefasst, alle anderen als true. Das Ergebnis von 0 || -1 lautet daher -1, und !! || "!?" wird zu "!?" ausgewertet.

Der Operator && geht ähnlich vor, aber anderes herum. Kann der Wert auf der linken Seite in false umgewandelt werden, so wird dieser Wert zurückgegeben, anderenfalls der Wert auf der rechten Seite.

Eine weitere wichtige Eigenschaft dieser beiden Operatoren besteht darin, dass der Teil auf ihrer rechten Seite nur dann ausgewertet wird, wenn es notwendig ist. So spielt es bei true || X keine Rolle, was X ist – selbst wenn es ein Teil eines Programms ist, der irgendetwas wirklich Fürchterliches tut. Das Ergebnis lautet in jedem Fall true, und X wird niemals ausgewertet. Das Gleiche gilt auch für false && X, was stets false ist, weshalb X ignoriert wird. Dies wird als kurzgeschlossene Auswertung bezeichnet.

Der Bedingungsoperator verhält sich ähnlich. Von den beiden hinteren Werten wird nur derjenige ausgewertet, der ausgewählt wird.

1.8Zusammenfassung

In diesem Kapitel haben wir uns vier Typen von JavaScript-Werten angesehen: Zahlen, Strings, boolesche Werte und nichtdefinierte Werte.

Um diese Werte zu erstellen, geben Sie ihre Bezeichnung (true, null) oder ihren Wert (13, "abc") an. Mithilfe von Operatoren können Sie Werte kombinieren und transformieren. Wir haben Binäroperatoren für arithmetische Berechnungen (+, -, *, / und %), für die String-Verkettung (+) und für Vergleiche (, !=, , !==, <, >, <=, >=), logische binäre Operatoren (&&, ||), verschiedene unäre Operatoren (- zur Negation einer Zahl, ! zur Negation eines logischen Werts und typeof, um den Typ eines Werts zu ermitteln) sowie einen ternären Operator (?:) kennengelernt, der auf der Grundlage eines Wertes zwischen zwei anderen auswählt.

Mit diesen Kenntnissen können Sie JavaScript wie einen Taschenrechner verwenden, aber noch nicht viel mehr tun. Im nächsten Kapitel beginnen wir, diese Ausdrücke zu einfachen Programmen zu kombinieren.

»Mein Herz glüht hellrot unter meiner dünnen, durchscheinenden Haut, und sie müssen mir 10 cm3 JavaScript injizieren, um mich zurückzuholen. (Ich reagiere gut auf Giftstoffe im Blut.) Mann, dieser Stoff haut dir echt die Pfirsiche aus den Kiemen!«

– _why, Why’s (Poignant) Guide to Ruby

2Programmstruktur

In diesem Kapitel beginnen wir damit, Aufgaben zu erledigen, die tatsächlich die Bezeichnung Programmierung verdienen. Wir erweitern unsere Kenntnisse der Sprache JavaScript über die Nomen und Satzfragmente hinaus, die wir bereits kennengelernt haben, sodass wir sinnvolle Prosa schreiben können.

2.1Ausdrücke und Anweisungen

In Kapitel 1 haben wir Werte erstellt und Operatoren darauf angewendet, um neue Werte zu erhalten. Werte auf diese Weise zu erstellen, ist ein wesentlicher Bestandteil aller JavaScript-Programme. Um nützlich zu sein, muss dieser Bestandteil aber in eine umfassende Struktur eingebettet werden. Das ist es, womit wir uns als Nächstes beschäftigen werden.

Ein Codefragment, das einen Wert produziert, wird als Ausdruck bezeichnet. Jeder explizit niedergeschriebene Wert (z. B. 22 oder "psychoanalysis") ist ein Ausdruck. Steht ein Ausdruck in Klammern, so ist dies ebenfalls ein Ausdruck. Wird ein binärer Operator auf zwei Ausdrücke oder ein unärer Operator auf einen Ausdruck angewendet, ist auch das ein Ausdruck.

Das macht die Schönheit einer sprachgestützten Schnittstelle deutlich: Ausdrücke können andere Ausdrücke auf eine ähnliche Weise enthalten, wie Teilsätze in menschlichen Sprachen verschachtelt werden. Auch hier kann jeder Teilsatz wiederum seine eigenen Teilsätze enthalten usw. Damit können wir Ausdrücke erstellen, die beliebig komplizierte Berechnungen beschreiben.

Wenn ein Ausdruck einem Teilsatz entspricht, so entspricht eine JavaScript-Anweisung einem vollständigen Satz. Ein Programm wiederum ist eine Folge von Anweisungen.

Die einfachste Art von Anweisung ist ein Ausdruck mit einem abschließenden Semikolon. Das Folgende ist bereits ein Programm:

1;

!false;

Allerdings ist dies ein völlig nutzloses Programm. Ein Ausdruck braucht lediglich einen Wert hervorzurufen, der dann vom umgebenden Code genutzt werden kann. Eine Anweisung aber steht für sich allein. Daher ist sie nur dann sinnvoll, wenn sie sich auf die Welt auswirkt. Beispielsweise kann sie etwas auf dem Bildschirm darstellen, was sich als eine Änderung der Welt sehen lässt. Sie kann auch den internen Zustand des Computers auf eine Weise ändern, die sich auf nachfolgende Anweisungen auswirkt. Solche Änderungen werden als Nebenwirkungen bezeichnet (meistens leider jedoch aufgrund einer wortwörtlichen Fehlübersetzung aus dem Englischen als Seiteneffekte). Die Anweisungen im vorigen Beispiel dagegen produzieren nur die Werte 1 und true und verwerfen sie dann sofort wieder, ohne eine bleibenden Eindruck in der Welt zu hinterlassen. Wenn Sie dieses Programm ausführen, geschieht nichts, was man beobachten könnte.

In manchen Fällen erlaubt Ihnen JavaScript, auf das Semikolon am Ende einer Anweisung zu verzichten, in anderen Fällen dagegen muss es unbedingt vorhanden sein, da die nächste Zeile sonst als ein weiterer Bestandteil der Anweisung aufgefasst wird. Die Regeln dafür, wann das Semikolon gefahrlos weggelassen werden kann, sind ziemlich kompliziert und fehleranfällig. In diesem Buch erhält jede Anweisung ein Semikolon. Ich rate Ihnen, genauso vorzugehen, zumindest so lange, bis Sie mehr über die Feinheiten fehlender Semikolons gelernt haben.

2.2Bindungen

Wie erhält ein Programm seinen internen Status aufrecht? Wie merkt es sich etwas? Wir wissen bereits, wie wir aus alten Werten neue produzieren, aber dabei werden die alten Werte nicht geändert und die neuen müssen sofort verwendet werden, da sie sich sonst wieder in Wohlgefallen auflösen. Um Werte zu erfassen und festzuhalten, gibt es in JavaScript Bindungen oder Variablen:

Im vorstehenden Beispiel wird die Bindung caught erstellt und dazu genutzt, die Zahl festzuhalten, die durch die Multiplikation von 5 mit 5 produziert wird.

Nachdem eine Bindung definiert wurde, kann ihr Name als Ausdruck verwendet werden. Der Wert dieses Ausdrucks ist der Wert, den die Bindung zurzeit festhält. Betrachten Sie dazu das folgende Beispiel:

Stellen Sie sich Bindungen eher wie Tentakel und nicht wie Kisten vor. Sie enthalten keine Werte, sondern halten sie fest. Zwei Bindungen können auch auf denselben Wert verweisen. Ein Programm kann nur auf die Werte zugreifen, zu denen es noch einen Verweis hat. Wenn es sich an etwas erinnern muss, lässt es einen Tentakel wachsen, um es festzuhalten, oder greift mit einem bereits vorhandenen Tentakel danach.

Sehen wir uns dazu ein weiteres Beispiel an. Um sich zu merken, wie viele Euro Luigi Ihnen noch schuldet, erstellen Sie eine Bindung. Wenn er Ihnen 35 Euro zurückzahlt, geben Sie dieser Bindung einen neuen Wert:

Falls Sie eine Bindung definieren, ohne ihr einen Wert zu geben, hat der Tentakel nichts, was er festhalten kann, sondern endet in der Luft. Wenn Sie dann nach dem Wert dieser leeren Bindung fragen, erhalten Sie den Wert undefined.

Mit einer einzigen let-Anweisung können Sie mehrere Bindungen definieren, wobei die einzelnen Bindungen durch Kommata zu trennen sind:

Auch mit den Wörtern var und const lassen sich ähnlich wie mit let Bindungen erstellen:

Die erste Möglichkeit, var (kurz für »Variable«), ist die Art und Weise, in der Bindungen in JavaScript vor 2015 deklariert wurden. Auf die genauen Unterschiede zwischen var und let werde ich im nächsten Kapitel eingehen. Merken Sie sich zunächst nur, dass var größtenteils das Gleiche macht wie let. Wir werden es in diesem Buch allerdings selten verwenden, da es einige verwirrende Eigenschaften hat.

Das Wort const definiert eine konstante Bindung, die während ihrer gesamten Existenz auf denselben Wert zeigt. Das ist praktisch, um einem Wert einen Namen zu geben, sodass Sie später leichter darauf verweisen können.

2.3Namen von Bindungen

Als Namen von Bindungen können Sie beliebige Wörter verwenden. Die Namen können auch Ziffern enthalten – so ist etwa catch22 ein gültiger Name –, dürfen aber nicht mit einer Ziffer beginnen. Ebenfalls erlaubt sind Dollarzeichen und Unterstriche, aber keine anderen Satz- oder Sonderzeichen.

Wörter wie let, die eine besondere Bedeutung haben, sind Schlüsselwörter und dürfen nicht als Namen für Bindungen verwendet werden. Es gibt auch eine Reihe von Wörtern, die für die Verwendung in zukünftigen Versionen von JavaScript »reserviert« sind und ebenfalls nicht als mögliche Bindungsnamen bereitstehen. Die vollständige Liste der Schlüsselwörter ist ziemlich lang:

break case catch class const continue debugger default

delete do else enum export extends false finally for

function if implements import interface in instanceof let

new package private protected public return static super

switch this throw true try typeof var void while with yield

Machen Sie sich aber nicht die Mühe, diese Liste auswendig zu lernen! Wenn der Versuch, eine Bindung zu erstellen, zu einem unerwarteten Syntaxfehler führt, schauen Sie nach, ob Sie ein reserviertes Wort verwendet haben.

2.4Die Umgebung

Die Gesamtheit der Bindungen und ihrer Werte, die zu einem gegebenen Zeitpunkt vorhanden sind, wird als Umgebung bezeichnet. Auch beim Start eines Programms ist die Umgebung nicht leer, denn sie enthält immer die Bindungen, die zum Sprachstandard gehören, und Bindungen zur Interaktion mit dem umgebenden System. In einem Browser gibt es beispielsweise Funktionen zur Interaktion mit der gerade geladenen Website und zum Erfassen der Maus- und Tastatureingaben.

2.5Funktionen

Viele Werte, die in der Standardumgebung zur Verfügung stehen, haben den Typ von Funktionen. Eine Funktion ist ein Programmteil, der in einen Wert eingeschlossen ist. Solche Werte können angewendet werden, um das eingeschlossene Programm auszuführen. Beispielsweise hält in einer Browserumgebung die Bindung prompt eine Funktion fest, die ein kleines Dialogfeld anzeigt, um den Benutzer zu einer Eingabe aufzufordern. Diese Bindung wird wie folgt verwendet:

prompt("Enter passcode");

Bei der Ausführung einer Funktion wird davon gesprochen, dass sie aufgerufen oder angewendet wird. Um eine Funktion aufzurufen, können Sie ein Paar Klammern hinter einen Ausdruck setzen, der einen Funktionswert produziert. Gewöhnlich verwenden Sie dazu den Namen der Bindung, die die Funktion festhält. Die Werte in den Klammern werden dem Programm in der Funktion übergeben. In dem vorigen Beispiel nutzt die Funktion prompt den übergebenen String als den Text, den sie in dem Dialogfeld anzeigt. An Funktionen übergebene Werte werden als Argumente bezeichnet. Die Anzahl und der Typ der Argumente sind von Funktion zu Funktion unterschiedlich.

Die Funktion prompt wird in der modernen Webprogrammierung kaum verwendet, weil Sie dabei keine Kontrolle darüber haben, wie das resultierende Dialogfeld aussieht. Zum Herumspielen und Ausprobieren allerdings ist sie ganz nützlich.

2.6Die Funktion console.log

In den Beispielen habe ich console.log verwendet, um Werte auszugeben. Die meisten JavaScript-Systeme (darunter alle modernen Webbrowser und Node.js) weisen eine Funktion namens console.log auf, die ihre Argumente an ein Textausgabegerät schicken. In Browsern landet diese Ausgabe in der JavaScript-Konsole. Dieser Teil der Browseroberfläche ist normalerweise ausgeblendet, kann in den meisten Browsern aber mit bzw. auf dem Mac mit geöffnet werden. Wenn das nicht funktioniert, suchen Sie im Menü nach einem Eintrag, der »Entwicklertools« o. ä. heißt.

Bindungsnamen dürfen keine Punkte enthalten, aber in console.log ist einer vorhanden. Das liegt daran, dass es sich bei console.log nicht um eine einfache Bindung handelt, sondern um einen Ausdruck, der die Eigenschaft log von dem Wert abruft, der von der Bindung console festgehalten wird. Was das genau bedeutet, erfahren Sie im Abschnitt »Eigenschaften« auf S. 63.

2.7Rückgabewerte

Ein Dialogfeld einzublenden oder Text auf den Bildschirm zu schreiben, ist lediglich ein Seiteneffekt. Viele Funktionen sind gerade wegen ihrer Seiteneffekte nützlich. Funktionen können jedoch auch Werte produzieren. In diesem Fall müssen sie keine Seiteneffekte haben, um nützlich zu sein. Beispielsweise nimmt die Funktion Math.max eine beliebige Anzahl von Argumenten entgegen und gibt das größte davon zurück:

console.log(Math.max(2, 4));

// → 4

In diesem Fall spricht man davon, dass die Funktion einen Wert zurückgibt. Alles, was einen Wert produziert, wird in JavaScript als Ausdruck angesehen. Das wiederum bedeutet, dass Funktionsaufrufe innerhalb umfangreicherer Ausdrücke verwendet werden können. Im folgenden Beispiel wird Math.min, das Gegenteil von Math.max, innerhalb eines Additionsausdrucks verwendet:

console.log(Math.min(2, 4) + 100);

// → 102

Im nächsten Kapitel erfahren Sie, wie Sie Ihre eigenen Funktionen schreiben.

2.8Ablaufsteuerung

Wenn ein Programm mehrere Anweisungen enthält, werden diese von vorn nach hinten ausgeführt. Das folgende Beispielprogramm hat zwei Anweisungen, von denen die erste zur Eingabe einer Zahl auffordert und die zweite, die danach ausgeführt wird, das Quadrat dieser Zahl anzeigt:

Die Funktion Number wandelt einen Wert in eine Zahl um. Diese Konvertierung ist erforderlich, da das Ergebnis von prompt ein String-Wert ist, wir aber eine Zahl brauchen. Es gibt ähnliche Funktionen wie String und Boolean, die Werte in die entsprechenden Typen umwandeln.

Dieser geradlinige Programmablauf lässt sich durch das folgende, ziemlich triviale Diagramm darstellen:

2.9Bedingte Ausführung