Abschnitt 2 · Lektion 3
Zahlen
In vielen Sprachen gibt es mehrere Sorten Zahlen: ganze, gebrochene, kleine, große. JavaScript hat eine einzige. 42 und 19.99 liegen im selben Typ, und du musst dich nie entscheiden.
Das ist bequem und hat einen Preis, den diese Lektion zeigt.
Die Grundrechenarten
<h1>Ausgabe</h1>
<p>Was dieses Beispiel tut, steht in der Console.</p> console.log("Plus:", 7 + 3);
console.log("Minus:", 7 - 3);
console.log("Mal:", 7 * 3);
console.log("Geteilt:", 7 / 3);
// Der Rest, der beim Teilen übrig bleibt.
console.log("Rest:", 7 % 3);
// Hoch: die kleine Zwei aus dem Matheunterricht.
console.log("Hoch:", 2 ** 10);
// Punkt vor Strich gilt, und Klammern gehen vor.
console.log("Ohne Klammern:", 2 + 3 * 4);
console.log("Mit Klammern:", (2 + 3) * 4); Plus, minus, mal, geteilt schreiben sich, wie du es erwartest. Beachte, dass der Dezimaltrenner ein Punkt ist, kein Komma: 19.99, nicht 19,99. Ein Komma bedeutet in JavaScript etwas anderes, und console.log(19,99) gibt zwei Zahlen aus statt einer.
Zwei Zeichen kennst du vielleicht noch nicht:
% ist der Rest einer Division, auf Englisch modulo. 7 % 3 ist 1, weil 3 zweimal in 7 passt und 1 übrig bleibt.
** ist die Potenz. 2 ** 10 ist 2 hoch 10, also 1024.
Punkt vor Strich gilt wie in der Schule, und Klammern gehen vor. Eine Klammer mehr, als nötig wäre, hat noch nie jemandem geschadet und spart dem nächsten Leser eine Denkpause.
Wofür man den Rest wirklich braucht
% sieht nach Schulmathematik aus und ist einer der praktischsten Operatoren überhaupt.
<h1>Ausgabe</h1>
<p>Was dieses Beispiel tut, steht in der Console.</p> // Ist die Zahl gerade? Dann bleibt beim Teilen durch 2 kein Rest.
console.log("8 gerade?", 8 % 2 === 0);
console.log("7 gerade?", 7 % 2 === 0);
// Jedes dritte Element? Dann ist der Rest beim Teilen durch 3 null.
console.log("9 durch 3 teilbar?", 9 % 3 === 0);
// Sekunden in Minuten und Sekunden zerlegen.
const gesamt = 187;
console.log("Minuten:", Math.floor(gesamt / 60));
console.log("Sekunden:", gesamt % 60); Gerade oder ungerade. Bleibt beim Teilen durch 2 kein Rest, ist die Zahl gerade. Das brauchst du zum Beispiel, um jede zweite Zeile einer Tabelle einzufärben.
Jedes n-te Element. Dieselbe Idee mit einer anderen Zahl. zaehler % 3 === 0 trifft jedes dritte.
Etwas zerlegen. 187 Sekunden sind 3 Minuten und 7 Sekunden. Die Minuten bekommst du mit einer abgerundeten Division, die Sekunden mit dem Rest.
Die drei Zeilen mit === sind ein Vorgriff: drei Gleichheitszeichen fragen, ob zwei Werte gleich sind, und liefern true oder false. Warum es drei sind und nicht zwei, klärt Abschnitt 3 ausführlich.
Falle eins: Kommazahlen sind ungenau
<h1>Ausgabe</h1>
<p>Was dieses Beispiel tut, steht in der Console.</p> // Das ist kein Tippfehler, das ist wirklich das Ergebnis.
console.log(0.1 + 0.2);
// Und deshalb ist auch der Vergleich falsch.
console.log(0.1 + 0.2 === 0.3);
// In Cent gerechnet stimmt alles, denn das sind ganze Zahlen.
const einsInCent = 10;
const zweiInCent = 20;
console.log("Summe in Cent:", einsInCent + zweiInCent);
// Runden macht aus einer krummen Zahl wieder eine ganze.
console.log("Gerundet:", Math.round(2378.81)); 0.1 + 0.2 ergibt 0.30000000000000004. Das ist kein Fehler in JavaScript, und es ist auch kein Fehler in deinem Computer. Fast jede Sprache verhält sich so.
Der Grund: Der Computer speichert Zahlen im Zweiersystem, also als Summe von Halben, Vierteln, Achteln und so weiter. 0.5 geht auf, das ist genau ein Halbes. 0.1 geht nicht auf, genauso wenig wie ein Drittel im Zehnersystem aufgeht: 0,3333… hört nie auf. Der Computer bricht irgendwo ab, und der winzige Rest macht sich beim Addieren bemerkbar.
Für die Anzeige ist das egal, niemand sieht die vierzehnte Nachkommastelle. Bei Vergleichen ist es fatal: 0.1 + 0.2 === 0.3 ist false, und wer darauf eine Bedingung baut, sucht lange.
Tipp beide Zeilen in die Eingabezeile der Console, erst 0.1 + 0.2 und dann 0.1 + 0.2 === 0.3. Die erste Antwort ist die lange Zahl, die zweite ist false. Das ist eine der Stellen, an denen Leute dem Text nicht glauben und es lieber selbst sehen wollen, und dafür ist die Zeile da.
Die Lösung ist erfreulich unspektakulär: Rechne Geld in Cent. Ein Preis von 19,99 Euro ist die Zahl 1999. Ganze Zahlen sind exakt, du kannst sie beliebig addieren und multiplizieren. Erst ganz am Ende, wenn du den Betrag anzeigst, teilst du durch 100. Deshalb heißt in diesem Kurs jede Geldvariable ...InCent.
Wenn dabei doch eine krumme Zahl entsteht, weil du zum Beispiel Prozente gerechnet hast, macht Math.round daraus wieder eine ganze. Es rundet ab einem halben nach oben, aus 2.5 wird also 3. Bei negativen Zahlen ist es nicht ganz so, wie man erwartet: Math.round(-2.5) ist -2 und nicht -3, denn „nach oben” heißt hier wirklich nach oben und nicht „vom Nullpunkt weg”. Nachschlagen kannst du das in der Eingabezeile, ausführlich wird es in Lektion 8.4. Daneben gibt es Math.floor, das immer abrundet, und Math.ceil, das immer aufrundet.
Falle zwei: NaN
<h1>Ausgabe</h1>
<p>Was dieses Beispiel tut, steht in der Console.</p> // Aus einem Wort lässt sich keine Zahl machen.
const kaputt = Number("Hallo");
console.log("Ergebnis:", kaputt);
console.log("Typ:", typeof kaputt);
// NaN ist sich selbst ungleich. Das ist kein Scherz.
console.log("Vergleich mit sich selbst:", kaputt === kaputt);
// Deshalb fragt man so danach.
console.log("Ist es NaN?", Number.isNaN(kaputt));
// Rechnen mit NaN ergibt wieder NaN, es steckt alles an.
console.log("Weitergerechnet:", kaputt + 10); NaN steht für „not a number” und ist das Ergebnis jeder Rechnung, die keinen Sinn ergibt. Der Versuch, aus dem Wort Hallo eine Zahl zu machen, liefert NaN.
Drei Eigenschaften machen es unangenehm:
Sein Typ ist number. Das klingt wie ein Widerspruch und ist Absicht: NaN ist der Platz im Zahlenbereich, der für „hier hätte eine Zahl stehen sollen” reserviert ist. typeof hilft dir hier also nicht.
Es ist sich selbst ungleich. NaN === NaN ist false. Das ist der einzige Wert in JavaScript mit dieser Eigenschaft. Du kannst also nicht if (wert === NaN) schreiben, das trifft nie zu. Stattdessen gibt es Number.isNaN(wert), und das ist die einzige zuverlässige Art zu fragen.
Es steckt an. Jede Rechnung mit NaN ergibt wieder NaN. Ein einziger kaputter Wert weit oben zieht sich durch die ganze Kette, und am Ende steht NaN in der Anzeige, ohne dass die letzte Zeile schuld wäre. Wenn du das siehst, such nach der ersten Stelle, an der eine Zahl aus einer Eingabe entstanden ist.
Es gibt noch einen zweiten Sonderwert: Infinity, das Ergebnis von 1 / 0. In der Praxis triffst du ihn selten, und wenn, dann als Zeichen dafür, dass irgendwo eine Null steht, wo keine hingehört.
Zum Mitnehmen
Rechne Geld nie in Euro, sondern in Cent. Dann sind es ganze Zahlen, und ganze Zahlen sind exakt.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
Was in dieser Lektion steckt
-
Artikel mit 4 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe im Editor, direkt im Browser geprüft
Öffnet sich mit dem Basis Konto.