
Zum Anzeigen einer Zahl nimmst du Intl.NumberFormat oder die Kurzform toLocaleString(): (1234.5).toLocaleString('fr-FR', { minimumFractionDigits: 2 }) ergibt „1 234,50“, und die Option style: 'currency' ergänzt die Währung. Zum Runden ohne Anzeige nimmst du Math.round(n * 100) / 100; toFixed(2) rundet ebenfalls, gibt aber einen String zurück.
Eine Zahl wird als Number berechnet und als String angezeigt: „1 234,50 €“, „25,6 %“, „1,4 k Aufrufe“. Dazwischen musst du runden, ein Tausendertrennzeichen setzen, Komma oder Punkt wählen. JavaScript erledigt das alles ohne Bibliothek, mit toFixed, toLocaleString und vor allem Intl.NumberFormat. Alle Ausgaben unten wurden unter Node.js 22 ausgeführt.
Eine Zahl runden
Math.round, Math.floor, Math.ceil, Math.trunc
Math.round(2.5); // 3 : zum nächsten Wert, .5 geht nach oben
Math.round(-2.5); // -2 : Richtung +unendlich, nicht „weg von null“
Math.floor(4.7); // 4 : nach unten
Math.floor(-4.2); // -5
Math.ceil(4.2); // 5 : nach oben
Math.trunc(-4.7); // -4 : schneidet die Nachkommastellen ab, egal welches VorzeichenDiese Funktionen kennen nur ganze Zahlen. Um auf zwei Nachkommastellen zu runden, multiplizierst du, rundest und teilst wieder:
Math.round(1.345 * 100) / 100; // 1.35
Math.round(1.005 * 100) / 100; // 1 : erwartet war 1.01, siehe untenDie Falle der binären Nachkommastellen
1.005 existiert binär nicht: Gespeichert wird 1.00499999…, und daraus wird beim Runden 1.00. Das ist kein Bug von JavaScript, sondern das Format IEEE 754, das alle Sprachen teilen. Zwei Gegenmittel:
// 1. Den Darstellungsfehler vor dem Runden korrigieren
Math.round((1.005 + Number.EPSILON) * 100) / 100; // 1.01
// 2. Nie Nachkommastellen speichern: Preise in ganzen Cent
const prixCentimes = 1005;
(prixCentimes / 100).toFixed(2); // '10.05'Das zweite ist die Regel für alles, was mit Geld zu tun hat: Ganze Cent zu addieren ergibt nie 0.30000000000000004.
toFixed(): runden für die Anzeige
(1234.5678).toFixed(2); // '1234.57'
(2.5).toFixed(0); // '3'
(1.005).toFixed(2); // '1.00' : dieselbe Binärfalle wie bei Math.round
(0.1 + 0.2).toFixed(2); // '0.30' : genau dafür ist es da
typeof (1.5).toFixed(2); // 'string'
(1.5).toFixed(2) + 1; // '1.501' : Verkettung, keine AdditiontoFixed gibt einen String zurück. Für die Anzeige ist das perfekt, für die Rechnung gefährlich: Wandle mit Number() um, wenn du den Wert weiterverwenden musst. Und sein Dezimaltrennzeichen ist immer ein Punkt; für das französische Komma führt der Weg über toLocaleString.
Tausendertrennzeichen und französisches Format: toLocaleString()
const n = 1234567.891;
n.toLocaleString('fr-FR'); // '1 234 567,891'
n.toLocaleString('en-US'); // '1,234,567.891'
n.toLocaleString('de-DE'); // '1.234.567,891'
(1234.5).toLocaleString('fr-FR', { minimumFractionDigits: 2 }); // '1 234,50'
(3.14159).toLocaleString('fr-FR', { maximumFractionDigits: 2 }); // '3,14'Eine Methode, drei nationale Konventionen, keine einzige Zeile Formatierungscode. Zwei Anmerkungen:
- Das französische Tausendertrennzeichen ist kein gewöhnliches Leerzeichen, sondern ein schmales geschütztes Leerzeichen (U+202F). Es verhindert, dass „1 234“ am Zeilenende umbricht. Musst du es entfernen, filtere mit
/\s/g, nicht mit' '. - Ohne Sprachargument nimmt
toLocaleString()die des Browsers oder des Systems. Für eine stabile Ausgabe gibst du immer'fr-FR'an.
Intl.NumberFormat: Währung, Prozent, Einheiten
toLocaleString ist eine Abkürzung zu Intl.NumberFormat. Das vollständige Objekt wird einmal erzeugt und wiederverwendet, was zählt, sobald du eine Liste oder eine Tabelle formatierst.
const euros = new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' });
euros.format(1234.5); // '1 234,50 €'
const dollars = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
dollars.format(1234.5); // '$1,234.50'
const pourcent = new Intl.NumberFormat('fr-FR', { style: 'percent', maximumFractionDigits: 1 });
pourcent.format(0.256); // '25,6 %' : der Wert ist ein Verhältnis, 0.256 und nicht 25.6
const km = new Intl.NumberFormat('fr-FR', { style: 'unit', unit: 'kilometer' });
km.format(12.5); // '12,5 km'
const go = new Intl.NumberFormat('fr-FR', { style: 'unit', unit: 'gigabyte', maximumFractionDigits: 2 });
go.format(2.35); // '2,35 Go'Der Währungsformatter setzt das Symbol je nach Sprache an die richtige Stelle (im Französischen dahinter, im Englischen davor), wählt die Anzahl der Nachkommastellen der Währung und fügt das geschützte Leerzeichen ein. Lauter Regeln, die du nicht mehr selbst schreiben musst.
Kompakte Notation: 1,4 k und 1 M
„1 400 Aufrufe“ als „1,4 k“ anzuzeigen oder „1 000 000“ als „1 M“ ist ein häufiger Bedarf. Die Option notation: 'compact' erledigt das, in der gewünschten Sprache.
const compact = new Intl.NumberFormat('fr-FR', { notation: 'compact' });
compact.format(1400); // '1,4 k'
compact.format(1000000); // '1 M'
new Intl.NumberFormat('en-US', { notation: 'compact' }).format(23000); // '23K'
new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 3 }).format(1230974); // '1.231M'
new Intl.NumberFormat('fr-FR', { notation: 'compact', compactDisplay: 'long' }).format(2500000); // '2,5 millions'Weitere nützliche Optionen:
new Intl.NumberFormat('fr-FR', { minimumIntegerDigits: 2 }).format(7); // '07'
new Intl.NumberFormat('fr-FR', { useGrouping: false }).format(1234567); // '1234567'
new Intl.NumberFormat('fr-FR', { signDisplay: 'always' }).format(12); // '+12'
new Intl.NumberFormat('en-US', { notation: 'scientific' }).format(676565765722); // '6.766E11'
new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 2, roundingMode: 'halfExpand' }).format(1.005); // '1,01'Die letzte Zeile verdient ein Wort: Intl.NumberFormat rundet ausgehend von der dezimalen Darstellung der Zahl, nicht von ihrer binären Näherung. Aus 1.005 wird tatsächlich „1,01“, wo toFixed noch „1.00“ lieferte. Ein Grund mehr, mit Intl zu formatieren statt von Hand.
Führende Nullen und andere Basen
String(7).padStart(2, '0'); // '07' : Stunden, Minuten, Rechnungsnummern
String(7).padStart(3, '0'); // '007'
(255).toString(16); // 'ff' : hexadezimal, für eine CSS-Farbe
(255).toString(2); // '11111111' : binär
(123.456).toPrecision(4); // '123.5' : Gesamtzahl der signifikanten Stellen
(1234.5678).toExponential(2); // '1.23e+3'Zwei Verhaltensweisen von toString(), die man kennen sollte: oberhalb von 1021 und unterhalb von 10−6 wechselt JavaScript in die wissenschaftliche Notation ((1e21).toString() ergibt '1e+21', (0.0000001).toString() ergibt '1e-7'). toFixed oder Intl.NumberFormat mit notation: 'standard' behalten die ausgeschriebene Form.
Die umgekehrte Operation
Ein formatierter String lässt sich nicht einfach zurückwandeln: Number('1 234,50') ergibt NaN. Du musst die Leerzeichen entfernen und das Komma ersetzen, bevor du umwandelst. Das vollständige Vorgehen steht in String in Zahl umwandeln in JavaScript.
Und Numeral.js?
Die erste Fassung dieses Artikels stellte Numeral.js vor, eine Bibliothek mit kompakter Formatsprache: numeral(50000).format('0,0') für „50,000“, '0a' für „23k“, '0.00b' für „2.35GB“, '0o' für „23rd“. Sie steckt noch in vielen Projekten und ihre Syntax ist angenehm.
import numeral from 'numeral';
numeral(50000).format('0,0'); // 50,000
numeral(23000).format('0a'); // 23k
numeral(2348895676).format('0.00b'); // 2.35GBAber ihre letzte Version, die 2.0.6, stammt vom März 2017 und das Projekt wird nicht mehr gepflegt: Die Locales sind eingefroren und das französische Trennzeichen ist nicht das erwartete schmale Leerzeichen. Für ein neues Projekt deckt Intl.NumberFormat dieselben Bedürfnisse ab (Tausender, kompakt, Währung, Prozent), ohne Abhängigkeit, mit den echten Konventionen jeder Sprache und ohne Gewicht im Bundle. Behalte Numeral dort, wo es schon steckt; füge es nicht mehr hinzu.
Zusammenfassung
| Bedarf | Werkzeug | Beispiel |
|---|---|---|
| Runden zum Weiterrechnen | Math.round(n * 100) / 100 oder ganze Cent | 1.35 |
| Runden zum Anzeigen, mit Dezimalpunkt | toFixed(2) | '1234.57' |
| Französisches Format, Tausender und Komma | toLocaleString('fr-FR') | '1 234 567,891' |
| Währung, Prozent, Einheit | Intl.NumberFormat + style | '1 234,50 €' |
| 1,4 k / 1 M | notation: 'compact' | '1,4 k' |
| Führende Nullen | padStart(2, '0') | '07' |
Häufige Fehler
(1.5).toFixed(2) + 1 ergibt „1.501“: toFixed gibt einen String zurück, die Addition verkettet. Wandle mit Number() um, wenn du weiterrechnen musst.(1.005).toFixed(2) ergibt „1.00“, weil 1.005 binär als 1.00499999… gespeichert wird. Für kaufmännisches Runden rechne in ganzen Cent.toLocaleString('fr-FR') für ein normales halten Das französische Tausendertrennzeichen ist ein schmales geschütztes Leerzeichen (U+202F). Ein replace(' ', '') entfernt es nicht; nimm /\s/g.format() für jeden Wert auf.

