
Per mostrare un numero, usa Intl.NumberFormat o la sua scorciatoia toLocaleString(): (1234.5).toLocaleString('fr-FR', { minimumFractionDigits: 2 }) dà «1 234,50», e l'opzione style: 'currency' aggiunge la valuta. Per arrotondare senza mostrare, Math.round(n * 100) / 100; toFixed(2) arrotonda anche lui ma restituisce una stringa.
Un numero si calcola in Number e si mostra come stringa: «1 234,50 €», «25,6 %», «1,4 k visualizzazioni». In mezzo bisogna arrotondare, mettere un separatore delle migliaia, scegliere la virgola o il punto. JavaScript fa tutto questo senza librerie grazie a toFixed, toLocaleString e soprattutto Intl.NumberFormat. Tutte le uscite qui sotto sono state eseguite con Node.js 22.
Arrotondare un numero
Math.round, Math.floor, Math.ceil, Math.trunc
Math.round(2.5); // 3 : al più vicino, .5 sale
Math.round(-2.5); // -2 : verso +Infinito, non «lontano da zero»
Math.floor(4.7); // 4 : verso il basso
Math.floor(-4.2); // -5
Math.ceil(4.2); // 5 : verso l'alto
Math.trunc(-4.7); // -4 : taglia la parte decimale, qualunque sia il segnoQueste funzioni conoscono solo l’intero. Per arrotondare a due decimali si moltiplica, si arrotonda, si divide:
Math.round(1.345 * 100) / 100; // 1.35
Math.round(1.005 * 100) / 100; // 1 : atteso 1.01, vedi sottoLa trappola dei decimali binari
1.005 non esiste in binario: il numero memorizzato vale 1.00499999… e quindi si arrotonda a 1.00. Non è un bug di JavaScript ma del formato IEEE 754, comune a tutti i linguaggi. Due rimedi:
// 1. Correggere l'errore di rappresentazione prima di arrotondare
Math.round((1.005 + Number.EPSILON) * 100) / 100; // 1.01
// 2. Non memorizzare mai decimali: i prezzi in centesimi interi
const prixCentimes = 1005;
(prixCentimes / 100).toFixed(2); // '10.05'Il secondo è la regola per tutto ciò che riguarda il denaro: sommare centesimi interi non produce mai 0.30000000000000004.
toFixed(): arrotondare per mostrare
(1234.5678).toFixed(2); // '1234.57'
(2.5).toFixed(0); // '3'
(1.005).toFixed(2); // '1.00' : stessa trappola binaria di Math.round
(0.1 + 0.2).toFixed(2); // '0.30' : serve proprio a questo
typeof (1.5).toFixed(2); // 'string'
(1.5).toFixed(2) + 1; // '1.501' : concatenazione, non addizionetoFixed restituisce una stringa. È perfetto per la visualizzazione, pericoloso per il calcolo: converti con Number() se devi riutilizzare il valore. E il suo separatore decimale è sempre il punto; per la virgola francese, passa da toLocaleString.
Separatore delle migliaia e formato francese: 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'Un metodo, tre convenzioni nazionali, nessuna riga di codice di formattazione. Due precisazioni:
- Il separatore delle migliaia francese non è uno spazio ordinario ma uno spazio stretto unificatore (U+202F). Impedisce che «1 234» si spezzi a fine riga. Se devi toglierlo, filtra con
/\s/g, non con' '. - Senza argomento di lingua,
toLocaleString()prende quella del browser o del sistema. Per un risultato stabile, indica sempre'fr-FR'.
Intl.NumberFormat: valuta, percentuale, unità
toLocaleString è una scorciatoia verso Intl.NumberFormat. L’oggetto completo si crea una volta e si riutilizza, cosa che conta appena formatti una lista o una tabella.
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 %' : il valore è un rapporto, 0.256 e non 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'Il formattatore di valuta mette il simbolo al posto giusto secondo la lingua (dopo in francese, prima in inglese), sceglie il numero di decimali della moneta e inserisce lo spazio unificatore. Altrettante regole che non devi più scrivere.
Notazione compatta: 1,4 k e 1 M
Mostrare «1 400 visualizzazioni» come «1,4 k», o «1 000 000» come «1 M», è un bisogno comune. L’opzione notation: 'compact' lo fa, nella lingua che vuoi.
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'Altre opzioni utili:
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'L’ultima riga merita una parola: Intl.NumberFormat arrotonda a partire dalla rappresentazione decimale del numero, non dalla sua approssimazione binaria. 1.005 diventa davvero «1,01», là dove toFixed dava «1.00». È una ragione in più per formattare con Intl invece che a mano.
Zeri iniziali e altre basi
String(7).padStart(2, '0'); // '07' : ore, minuti, numeri di fattura
String(7).padStart(3, '0'); // '007'
(255).toString(16); // 'ff' : esadecimale, per un colore CSS
(255).toString(2); // '11111111' : binario
(123.456).toPrecision(4); // '123.5' : numero totale di cifre significative
(1234.5678).toExponential(2); // '1.23e+3'Due comportamenti di toString() da conoscere: oltre 1021 e sotto 10−6, JavaScript passa alla notazione scientifica ((1e21).toString() dà '1e+21', (0.0000001).toString() dà '1e-7'). toFixed o Intl.NumberFormat con notation: 'standard' mantengono la scrittura estesa.
L’operazione inversa
Una stringa formattata non si riconverte così com’è: Number('1 234,50') vale NaN. Bisogna togliere gli spazi e sostituire la virgola prima di convertire. Il procedimento completo è in Convertire una stringa in numero in JavaScript.
E Numeral.js?
La prima versione di questo articolo presentava Numeral.js, una libreria dal formato compatto: numeral(50000).format('0,0') per «50,000», '0a' per «23k», '0.00b' per «2.35GB», '0o' per «23rd». È ancora presente in molti progetti e la sua sintassi è piacevole.
import numeral from 'numeral';
numeral(50000).format('0,0'); // 50,000
numeral(23000).format('0a'); // 23k
numeral(2348895676).format('0.00b'); // 2.35GBMa la sua ultima versione, la 2.0.6, è del marzo 2017 e il progetto non è più mantenuto: le locale sono congelate e il separatore francese non è lo spazio stretto che ci si aspetta. Per un progetto nuovo, Intl.NumberFormat copre gli stessi bisogni (migliaia, compatto, valuta, percentuale) senza dipendenze, con le convenzioni reali di ogni lingua e peso nullo nel bundle. Tieni Numeral dov’è già; non aggiungerlo più.
Riepilogo
| Esigenza | Strumento | Esempio |
|---|---|---|
| Arrotondare per calcolare | Math.round(n * 100) / 100 o centesimi interi | 1.35 |
| Arrotondare per mostrare, punto decimale | toFixed(2) | '1234.57' |
| Formato francese, migliaia e virgola | toLocaleString('fr-FR') | '1 234 567,891' |
| Valuta, percentuale, unità | Intl.NumberFormat + style | '1 234,50 €' |
| 1,4 k / 1 M | notation: 'compact' | '1,4 k' |
| Zeri iniziali | padStart(2, '0') | '07' |
Errori frequenti
(1.5).toFixed(2) + 1 dà «1.501»: toFixed restituisce una stringa e l'addizione concatena. Converti con Number() se devi ricalcolare.(1.005).toFixed(2) vale «1.00» perché 1.005 è memorizzato come 1.00499999… in binario. Per un arrotondamento contabile, lavora in centesimi interi.toLocaleString('fr-FR') con uno spazio normale Il separatore delle migliaia francese è uno spazio stretto unificatore (U+202F). Un replace(' ', '') non lo toglie; usa /\s/g.format() su ogni valore.

