Zum Inhalt springen

Variablen, Typen und Operatoren

Diese Einheit frischt auf, wie JavaScript Werte speichert, welche Typen es kennt und wie es Werte vergleicht. Das brauchst du überall im Kurs, denn Vue-Code besteht zum grössten Teil aus gewöhnlichem JavaScript.

Lernziele

Nach dieser Einheit kannst du

  • Variablen mit const und let anlegen und begründen, welche du wählst,
  • die primitiven Typen von JavaScript nennen und mit typeof prüfen,
  • Werte mit === vergleichen und erklären, warum == Überraschungen bringt,
  • sagen, welche Werte als falsch gelten, und Standardwerte mit ?? setzen.

Eine Variable gibt einem Wert einen Namen. In modernem JavaScript legst du sie mit const oder let an. Eine Variable mit const lässt sich nicht neu zuweisen, eine mit let schon. Nimm const, wo immer es geht, und let nur, wenn sich der Wert später ändern muss, etwa bei einem Zähler.

const deposit = 20
deposit = 30 // TypeError: Assignment to constant variable.

const schützt nur die Variable, nicht ihren Inhalt. Zeigt eine Konstante auf ein Objekt, kannst du seine Felder trotzdem ändern. Mehr dazu steht in der Einheit Objekte und Arrays.

Das ältere var findest du noch in alten Anleitungen. Es gilt in der ganzen Funktion statt nur im Block, in dem es steht, und führt deshalb leicht zu Fehlern. Im Kurs kommt es nicht vor.

JavaScript kennt sieben primitive Typen. Im Alltag begegnen dir fünf davon.

TypBeispielBedeutung
string'Bohrmaschine'Text
number20, 12.5Zahl, ganz oder mit Stellen nach dem Punkt
booleantrue, falseWahrheitswert
undefinedundefinednoch kein Wert zugewiesen
nullnullabsichtlich kein Wert

Dazu kommen bigint für sehr grosse ganze Zahlen und symbol für eindeutige Schlüssel, beide brauchst du im Kurs nicht. Alles andere ist ein Objekt, auch Arrays und Funktionen. Mit typeof fragst du, welchen Typ ein Wert hat.

types.mjs
const name = 'Bohrmaschine'
const deposit = 20
const available = true
const borrowedBy = null
let returnDate
console.log(typeof name, typeof deposit, typeof available)
console.log(typeof borrowedBy, typeof returnDate)

typeof liefert den Typ als Text. Bei null meldet es object. Das ist ein alter Fehler der Sprache, der aus Rücksicht auf bestehenden Code nie korrigiert wurde. Ob ein Wert null ist, prüfst du deshalb mit value === null. returnDate hat nie einen Wert bekommen und ist darum undefined.

=== vergleicht Wert und Typ. == wandelt die Werte vorher um, wenn ihre Typen verschieden sind, und kommt dabei zu Ergebnissen, die kaum jemand erwartet. Verwende deshalb immer === und !==.

equality.mjs
console.log(20 === '20', 20 == '20')
console.log(Number('zwanzig'), Number.isNaN(Number('zwanzig')))
console.log(Boolean(''), Boolean('0'), Boolean(0), Boolean([]))

Die erste Zeile zeigt den Unterschied. 20 === '20' ist falsch, weil eine Zahl und ein Text verschiedene Typen haben. 20 == '20' wandelt den Text in eine Zahl um und ist wahr. Werte aus Formularfeldern sind immer Text. Willst du mit ihnen rechnen, wandelst du sie mit Number(...) ausdrücklich um.

Lässt sich ein Text nicht als Zahl lesen, liefert Number den Wert NaN, «Not a Number». NaN ist nicht einmal mit sich selbst gleich, darum prüfst du mit Number.isNaN.

Die dritte Zeile zeigt, welche Werte als wahr oder falsch gelten. In einer Bedingung wandelt JavaScript jeden Wert in einen Wahrheitswert um. Als falsch gelten false, die Zahl 0, der leere Text '', null, undefined und NaN, auf Englisch heissen sie «falsy». Alles andere gilt als wahr, auch der Text '0' und ein leeres Array.

Oft fehlt ein Wert, und du willst an seiner Stelle einen Standardwert einsetzen. Dafür gibt es zwei Operatoren, die sich in einem Punkt unterscheiden.

fallback.mjs
const input = 0
console.log(input || 20)
console.log(input ?? 20)
const note = ''
console.log(note || 'keine Bemerkung')
console.log(note ?? 'keine Bemerkung')

a || b liefert b, sobald a als falsch gilt. Bei einem Pfand ist das ein Fehler, denn 0 ist ein gültiges Pfand, und input || 20 macht daraus 20. a ?? b liefert b nur, wenn a null oder undefined ist. Bei der Bemerkung zeigt sich der Unterschied von der anderen Seite. Für || gilt der leere Text als fehlend, für ?? ist er ein Wert, darum gibt die letzte Zeile eine leere Zeile aus.

Nimm ??, wenn 0 oder ein leerer Text gültige Werte sind, und || nur dann, wenn du jeden falschen Wert ersetzen willst.

FehlerWas hilft
Mit dem Inhalt eines Formularfelds wird gerechnet, und '20' + 5 ergibt '205'.Den Text zuerst mit Number(...) in eine Zahl umwandeln und mit Number.isNaN prüfen.
== statt ===, und 0 == '' ist plötzlich wahr.Immer === und !== verwenden.
value || 20 ersetzt auch ein Pfand von 0.value ?? 20 verwenden, wenn 0 ein gültiger Wert ist.
typeof value === 'object' soll prüfen, ob ein Objekt da ist, und ist auch bei null wahr.Zusätzlich value !== null prüfen.
x === NaN ist nie wahr.Number.isNaN(x) verwenden.
Ein KI-Assistent schreibt var.const verwenden und let nur, wenn sich der Wert ändert.

Aufgabe Einstieg

Sag für jeden der Werte 50, '50', false, undefined und null voraus, was typeof meldet. Schreib danach ein Programm, das alle fünf Typen in einer Zeile ausgibt, und vergleiche.

Lösung
solution-1.mjs
console.log(typeof 50, typeof '50', typeof false, typeof undefined, typeof null)

Die Ausgabe ist number string boolean undefined object. Die Anführungszeichen machen aus 50 einen Text. Bei null meldet typeof den alten Fehler object.

Aufgabe Vertiefung

Schreib eine Funktion depositOrDefault(value), die ein Pfand zurückgibt oder 20, wenn keines angegeben ist. Ein Pfand von 0 ist erlaubt und muss erhalten bleiben. Teste sie mit 50, 0, null und undefined.

Lösung
solution-2.mjs
function depositOrDefault(value) {
return value ?? 20
}
console.log(depositOrDefault(50), depositOrDefault(0), depositOrDefault(null), depositOrDefault(undefined))

Die Ausgabe ist 50 0 20 20. Mit value || 20 käme beim Pfand von 0 ebenfalls 20 heraus, weil 0 als falsch gilt.

Aufgabe Knobelei

Rechne 0.1 + 0.2 und vergleiche das Ergebnis mit 0.3. Erkläre, was passiert. Finde dann einen Weg, mit Beträgen in Franken so zu rechnen, dass der Vergleich stimmt.

Lösung
solution-3.mjs
const francs = 0.1 + 0.2
console.log(francs, francs === 0.3)
// Amounts in Rappen are whole numbers, and whole numbers add up exactly
const rappen = 10 + 20
console.log(rappen, rappen === 30, (rappen / 100).toFixed(2))

JavaScript speichert Zahlen im Binärsystem mit 64 Bit. 0.1 und 0.2 lassen sich darin nicht genau darstellen, so wie ein Drittel im Dezimalsystem nicht aufgeht. Die Summe ist deshalb 0.30000000000000004 und nicht gleich 0.3. Ganze Zahlen bis gut 9 Billiarden stellt JavaScript dagegen genau dar. Darum rechnen viele Programme mit Rappen statt mit Franken und wandeln erst für die Anzeige um, hier mit (rappen / 100).toFixed(2).

Texte und Abbildungen stehen unter CC BY-SA 4.0, der Code unter der MIT-Lizenz und die Daten des Kurses unter CC0 1.0. Die Schrift der Abbildungen ist Kalam unter der SIL Open Font License 1.1. Die Quellen liegen auf GitHub.