Ein Zahlentyp für (fast) alles
In den meisten Sprachen gibt es getrennte Typen für Ganzzahlen und Fließkommazahlen. JavaScript hatte historisch nur einen einzigen: den Number-Typ. Egal ob du 42, 3.14 oder -0.001 schreibst — du bekommst immer denselben primitiven Wert, nämlich eine 64-Bit-Fließkommazahl nach IEEE 754 (double precision).
Praktisch, oder? Kein Cast zwischen int und float, kein Overflow bei 2^31. Aber die Darstellung als Fließkommazahl hat ihren Preis — und Anfänger tappen regelmäßig in genau diese Falle. 2020 kam deshalb ein zweiter numerischer Typ dazu: BigInt. Er springt überall dort ein, wo Number an seine Grenzen stößt.
Die Sache mit der Fließkomma-Genauigkeit
Führ mal das hier aus:
Die erste Zeile gibt 0.30000000000000004 aus, die zweite false. Das ist keine Macke von JavaScript – Python, Java, C und jede andere Sprache, die IEEE-754-Floats nutzt, verhält sich exakt gleich.
Der Grund: 0.1 und 0.2 lassen sich im Binärsystem nicht exakt darstellen, genauso wie 1/3 im Dezimalsystem nicht sauber aufgeht. Gespeichert wird jeweils die nächstgelegene binäre Näherung, und die winzigen Fehler summieren sich. Das passende mentale Modell: Betrachte Number-Werte mit Nachkommastellen als Näherungen, die zufällig sehr dicht an dem liegen, was du hingeschrieben hast.
Für Geldbeträge heißt das: Speichere 19,99 € nicht als 19.99. Rechne stattdessen in Cent mit Ganzzahlen – also 1999 – und formatiere erst bei der Ausgabe. Das ist die wichtigste Gewohnheit, um der mangelnden Fließkomma-Genauigkeit in JavaScript aus dem Weg zu gehen.
Floats sicher vergleichen
Da ein Gleichheitsvergleich hier unzuverlässig ist, solltest du bei Bedarf mit einer Toleranz arbeiten:
Number.EPSILON steht für die kleinste Differenz zwischen 1 und der nächsten darstellbaren Zahl – eine brauchbare Standardtoleranz für Werte in der Nähe von 1. Bei besonders großen oder sehr kleinen Beträgen brauchst du dagegen eine Toleranz, die mit den Eingabewerten mitskaliert.
Der sichere Integer-Bereich in JavaScript
Ganze Zahlen bis zu einer bestimmten Größe werden in einem 64-Bit-Float exakt dargestellt. Darüber hinaus verlierst du Stück für Stück an Genauigkeit – Bit für Bit:
2^53 - 1 ist die letzte Ganzzahl, unterhalb derer wirklich jede Ganzzahl darstellbar ist. Darüber hinaus existieren manche Integer im Number-Typ schlicht nicht mehr – sie werden auf den nächstgelegenen Nachbarn gerundet. Genau hier lauert ein stiller Datenverlust: Wenn du 64-Bit-IDs aus einer Datenbank als einfache JSON-Zahlen einliest, kracht es früher oder später.
BigInt kommt ins Spiel
BigInt ist ein eigenständiger primitiver Typ für beliebig große Ganzzahlen. Du erzeugst einen BigInt, indem du ein n an ein Integer-Literal anhängst oder BigInt(...) aufrufst:
BigInts haben keine feste Obergrenze – sie sind nur durch den verfügbaren Speicher begrenzt. Sie sind das richtige Werkzeug für:
- Datenbank-IDs oder Snowflake-IDs von Twitter/X, die über
2^53hinausgehen. - Kryptografische Berechnungen.
- Jede Ganzzahlarithmetik, bei der exakte Ergebnisse wichtiger sind als reine Geschwindigkeit.
Für alltägliche Zähler, Array-Indizes oder Geldbeträge in Cent sind sie dagegen nicht das passende Werkzeug – der normale Number-Typ ist schneller und spielt mit jeder API der Sprache zusammen.
Rechnen mit BigInt
Alle gewohnten Operatoren funktionieren – solange beide Operanden BigInts sind:
Die Division schneidet Richtung Null ab – Nachkommastellen gibt es bei BigInts schlicht nicht. Wenn du einen Bruch brauchst, bist du wieder bei Number (oder bei einer Decimal-Bibliothek).
Typen nicht mischen
Die Regel, über die praktisch jeder einmal stolpert: Number und BigInt darfst du in derselben Expression nicht mischen.
Vergleiche sind die einzige Ausnahme — <, >, == wandeln über die Grenze hinweg um:
== hält sie also für gleich, === nicht. Wer bereits konsequent === verwendet (und das solltest du), sollte numerische Vergleiche zwischen beiden Typen als Warnsignal im Design betrachten – entscheide dich für eine Seite und konvertiere.
Umwandlung zwischen Number und BigInt
Zwei Konvertierungen, zwei Stolperfallen:
Der Weg Number → BigInt ist strikt: Dezimalstellen und NaN werfen einen Fehler. Umgekehrt, also BigInt → Number, ist nachgiebiger, dafür aber verlustbehaftet — alles oberhalb von MAX_SAFE_INTEGER wird gerundet. Wenn du einen BigInt vom Server bekommst und ihn umwandeln willst, frag dich lieber zweimal, ob das wirklich nötig ist.
Besondere Werte im Number-Typ
Wo wir gerade dabei sind: Im Number-Typ gibt es drei Werte, die mathematisch gesehen gar keine Zahlen sind:
Infinity und -Infinity tauchen auf, wenn du durch Null teilst oder den Wertebereich von Floats sprengst. NaN ("not a number") erscheint dagegen, wenn eine Rechenoperation kein sinnvolles Ergebnis liefert.
Eine bekannte Eigenheit: NaN ist nicht einmal zu sich selbst gleich — das ist kein Bug in JS, sondern so in IEEE 754 festgelegt. Zum Prüfen nimmst du Number.isNaN(x). Die ältere globale Funktion isNaN wandelt ihr Argument vorher in eine Zahl um und liefert deshalb falsche Ergebnisse (isNaN("hello") gibt true zurück). Greif also immer zu Number.isNaN.
Strings in Zahlen umwandeln
Nutzereingaben und JSON-Werte kommen oft als String an. Es gibt drei Wege, daraus eine Zahl zu machen:
Number() ist streng – alles, was nicht numerisch ist, liefert NaN. Ausnahmen sind der leere String und reine Whitespaces, die 0 ergeben. parseInt und parseFloat dagegen sind nachsichtig: Sie lesen so weit wie möglich und hören auf, sobald etwas Nicht-Numerisches kommt. Nimm das, was zu deinem Ziel passt, und prüfe das Ergebnis vorher auf NaN.
Wenn du BigInts aus Strings parsen willst, nutze BigInt("123") – die Funktion ist strikt und wirft bei ungültiger Eingabe einen Fehler.
Die wichtigsten Regeln auf einen Blick
- Für Zähler, Mathematik, Koordinaten und die meisten Alltagszahlen:
Number. - Für Geldbeträge: in ganzzahlige Cent umrechnen und
Numberverwenden, oder zu einer Decimal-Bibliothek greifen. - Für ganze Zahlen größer als
2^53(Datenbank-IDs, Kryptografie, Kombinatorik):BigIntmit demn-Suffix. - Floats mit einer Toleranz vergleichen, nie mit
===. - Ungültige Ergebnisse mit
Number.isNaNundNumber.isFiniteprüfen, nicht mit den globalen Varianten. NumberundBigIntnicht im selben Ausdruck mischen – immer explizit konvertieren.
Als Nächstes: null vs. undefined
JavaScript kennt zwei Arten, „kein Wert" auszudrücken – null und undefined – und die beiden sind nicht austauschbar. Im nächsten Kapitel schauen wir uns an, was jedes davon bedeutet, worin sie sich unterscheiden und wann du welches verwenden solltest.
Häufig gestellte Fragen
Warum ergibt 0.1 + 0.2 in JavaScript nicht 0.3?
Weil der Number-Typ in JavaScript ein 64-Bit-IEEE-754-Float ist — und 0.1 und 0.2 lassen sich binär nicht exakt darstellen. Heraus kommt 0.30000000000000004. Das ist kein Bug von JavaScript, sondern passiert genauso in Python, Java und überall sonst, wo dasselbe Float-Format genutzt wird. Für Geldbeträge rechnest du entweder in Cent (also mit ganzen Zahlen) oder nutzt eine Decimal-Bibliothek.
Was ist BigInt in JavaScript und wann brauche ich es?
BigInt ist ein eigener numerischer Primitiv-Typ für ganze Zahlen jenseits von Number.MAX_SAFE_INTEGER (2^53 - 1). Du erzeugst einen BigInt mit einem angehängten n — also 9007199254740993n — oder per BigInt(value). Sinnvoll ist das bei 64-Bit-Datenbank-IDs, in der Kryptografie oder überall dort, wo Präzision wichtiger ist als Geschwindigkeit.
Kann ich Number und BigInt in JavaScript mischen?
Nein. 1n + 1 wirft direkt einen TypeError: Cannot mix BigInt and other types. Du musst explizit konvertieren, entweder mit BigInt(n) oder Number(b). Vergleichsoperatoren wie < oder == funktionieren zwar typübergreifend, aber === liefert false, weil die Typen eben unterschiedlich sind.