
Pour afficher un nombre, utilisez Intl.NumberFormat ou son raccourci toLocaleString() : (1234.5).toLocaleString('fr-FR', { minimumFractionDigits: 2 }) donne « 1 234,50 », et l’option style: 'currency' ajoute la devise. Pour arrondir sans afficher, Math.round(n * 100) / 100. toFixed(2) arrondit aussi mais renvoie une chaîne.
Un nombre se calcule en Number et s’affiche en chaîne : « 1 234,50 € », « 25,6 % », « 1,4 k vues ». Entre les deux, il faut arrondir, placer un séparateur de milliers, choisir la virgule ou le point. JavaScript fait tout cela sans bibliothèque grâce à toFixed, toLocaleString et surtout Intl.NumberFormat. Toutes les sorties ci-dessous ont été exécutées sous Node.js 22.
Arrondir un nombre
Math.round, Math.floor, Math.ceil, Math.trunc
Math.round(2.5); // 3 : au plus proche, .5 monte
Math.round(-2.5); // -2 : vers +Infini, pas « loin de zéro »
Math.floor(4.7); // 4 : vers le bas
Math.floor(-4.2); // -5
Math.ceil(4.2); // 5 : vers le haut
Math.trunc(-4.7); // -4 : coupe la partie décimale, quel que soit le signeCes fonctions ne connaissent que l’entier. Pour arrondir à deux décimales, on multiplie, on arrondit, on divise :
Math.round(1.345 * 100) / 100; // 1.35
Math.round(1.005 * 100) / 100; // 1 : attendu 1.01, voir ci-dessousLe piège des décimales binaires
1.005 n’existe pas en binaire : le nombre stocké vaut 1.00499999… et s’arrondit donc à 1.00. Ce n’est pas un bug de JavaScript mais du format IEEE 754, commun à tous les langages. Deux parades :
// 1. Corriger l'erreur de représentation avant d'arrondir
Math.round((1.005 + Number.EPSILON) * 100) / 100; // 1.01
// 2. Ne jamais stocker de décimales : les prix en centimes entiers
const prixCentimes = 1005;
(prixCentimes / 100).toFixed(2); // '10.05'La seconde est la règle pour tout ce qui touche à l’argent : additionner des centimes entiers ne produit jamais 0.30000000000000004.
toFixed() : arrondir pour afficher
(1234.5678).toFixed(2); // '1234.57'
(2.5).toFixed(0); // '3'
(1.005).toFixed(2); // '1.00' : même piège binaire que Math.round
(0.1 + 0.2).toFixed(2); // '0.30' : c'est justement à ça qu'il sert
typeof (1.5).toFixed(2); // 'string'
(1.5).toFixed(2) + 1; // '1.501' : concaténation, pas additiontoFixed renvoie une chaîne. C’est parfait pour l’affichage, dangereux pour le calcul : convertissez avec Number() si vous devez réutiliser la valeur. Et son point décimal est toujours un point, pour la virgule française, passez par toLocaleString.
Séparateur de milliers et format français : 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'Une méthode, trois conventions nationales, aucune ligne de code de formatage. Deux précisions :
- Le séparateur de milliers français n’est pas un espace ordinaire mais une espace fine insécable (U+202F). Elle empêche la coupure « 1 234 » en fin de ligne. Si vous devez la retirer, filtrez avec
/\s/g, pas avec' '. - Sans argument de langue,
toLocaleString()prend celle du navigateur ou du système. Pour un rendu stable, indiquez toujours'fr-FR'.
Intl.NumberFormat : devise, pourcentage, unités
toLocaleString est un raccourci vers Intl.NumberFormat. L’objet complet se crée une fois et se réutilise, ce qui compte dès qu’on formate une liste ou un tableau.
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 %' : la valeur est un ratio, 0.256 et 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'Le formateur de devise place le symbole au bon endroit selon la langue (après en français, avant en anglais), choisit le nombre de décimales de la monnaie et insère l’espace insécable. Autant de règles qu’il ne faut plus coder.
Notation compacte : 1,4 k et 1 M
Afficher « 1 400 vues » en « 1,4 k » ou « 1 000 000 » en « 1 M » est un besoin courant. L’option notation: 'compact' le fait, dans la langue voulue.
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'Autres options utiles :
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'La dernière ligne mérite un mot : Intl.NumberFormat arrondit à partir de la représentation décimale du nombre, pas de son approximation binaire. 1.005 devient bien « 1,01 », là où toFixed donnait « 1.00 ». C’est une raison de plus de formater avec Intl plutôt qu’à la main.
Zéros initiaux et autres bases
String(7).padStart(2, '0'); // '07' : heures, minutes, numéros de facture
String(7).padStart(3, '0'); // '007'
(255).toString(16); // 'ff' : hexadécimal, pour une couleur CSS
(255).toString(2); // '11111111' : binaire
(123.456).toPrecision(4); // '123.5' : nombre total de chiffres significatifs
(1234.5678).toExponential(2); // '1.23e+3'Deux comportements de toString() à connaître : au-delà de 1021 et en dessous de 10−6, JavaScript bascule en notation scientifique ((1e21).toString() donne '1e+21', (0.0000001).toString() donne '1e-7'). toFixed ou Intl.NumberFormat avec notation: 'standard' gardent l’écriture développée.
L’opération inverse
Une chaîne formatée ne se reconvertit pas telle quelle : Number('1 234,50') vaut NaN. Il faut retirer les espaces et remplacer la virgule avant de convertir. La démarche complète est dans Convertir une chaîne en nombre en JavaScript.
Et Numeral.js ?
La première version de cet article présentait Numeral.js, une bibliothèque au format compact : numeral(50000).format('0,0') pour « 50,000 », '0a' pour « 23k », '0.00b' pour « 2.35GB », '0o' pour « 23rd ». Elle reste dans beaucoup de projets et sa syntaxe est agréable.
import numeral from 'numeral';
numeral(50000).format('0,0'); // 50,000
numeral(23000).format('0a'); // 23k
numeral(2348895676).format('0.00b'); // 2.35GBMais sa dernière version, la 2.0.6, date de mars 2017 et le projet n’est plus maintenu : les locales sont figées et le séparateur français n’est pas l’espace fine attendue. Pour un nouveau projet, Intl.NumberFormat couvre les mêmes besoins (milliers, compact, devise, pourcentage) sans dépendance, avec les vraies conventions de chaque langue et un poids nul dans le bundle. Gardez Numeral là où il est déjà, ne l’ajoutez plus.
Récapitulatif
| Besoin | Outil | Exemple |
|---|---|---|
| Arrondir pour calculer | Math.round(n * 100) / 100 ou centimes entiers | 1.35 |
| Arrondir pour afficher, point décimal | toFixed(2) | '1234.57' |
| Format français, milliers et virgule | toLocaleString('fr-FR') | '1 234 567,891' |
| Devise, pourcentage, unité | Intl.NumberFormat + style | '1 234,50 €' |
| 1,4 k / 1 M | notation: 'compact' | '1,4 k' |
| Zéros initiaux | padStart(2, '0') | '07' |
Erreurs fréquentes
(1.5).toFixed(2) + 1 donne « 1.501 » : toFixed renvoie une chaîne, l’addition concatène. Convertissez avec Number() si vous devez recalculer.(1.005).toFixed(2) vaut « 1.00 » parce que 1.005 est stocké comme 1.00499999… en binaire. Pour un arrondi financier, travaillez en centimes entiers.toLocaleString('fr-FR') par un espace normal Le séparateur de milliers français est une espace fine insécable (U+202F). Un replace(' ', '') ne la retire pas, utilisez /\s/g.format() sur chaque valeur.

