Cómo formatear números a 2 decimales en JavaScript
Muestra números con exactamente 2 decimales para precios, porcentajes y medidas
Introducción
Muchas aplicaciones necesitan mostrar números con un número fijo de decimales. Los precios suelen mostrar dos decimales como $19.99. Los porcentajes a menudo se muestran como 45.50%. Las medidas usan decimales consistentes para legibilidad como 3.14 metros.
Controlar los decimales asegura consistencia visual en toda tu aplicación. Sin formato explícito, JavaScript muestra números con decimales variables según su valor real. El número 5 se muestra como "5" mientras que 5.5 se muestra como "5.5", creando alineación y apariencia inconsistentes.
Esta lección muestra cómo formatear números a exactamente 2 decimales, o hasta 2 decimales, de una manera que respeta las diferentes convenciones locales.
Usar toFixed() para formato básico
El método toFixed() convierte un número a una cadena con un número especificado de decimales. Pasa el número de decimales como argumento.
const price = 19.9;
const formatted = price.toFixed(2);
console.log(formatted);
// Output: "19.90"
El método siempre muestra exactamente 2 decimales. Si el número tiene menos decimales, toFixed() rellena con ceros. Si tiene más decimales, el método redondea a 2 lugares.
const examples = [5, 5.5, 5.555, 5.999];
examples.forEach(num => {
console.log(num.toFixed(2));
});
// Output:
// "5.00"
// "5.50"
// "5.56"
// "6.00"
El método toFixed() devuelve una cadena, no un número. Esto es intencional porque los ceros finales tienen significado para la visualización pero se perderían si se devolvieran como número.
El problema de locale con toFixed()
El método toFixed() siempre usa un punto como separador decimal, independientemente del locale del usuario. Muchos países usan una coma como separador decimal en lugar de un punto.
const price = 19.99;
console.log(price.toFixed(2));
// Output: "19.99" (always uses period)
Para usuarios en Alemania, Francia, España y muchos otros países, esto se ve incorrecto. Esperan ver "19,99" en lugar de "19.99". El método toFixed() no puede producir resultados apropiados para la configuración regional.
Para formatear números correctamente para diferentes configuraciones regionales, utiliza la API Intl.NumberFormat.
Uso de Intl.NumberFormat para formateo según configuración regional
La API Intl.NumberFormat formatea números según las convenciones de la configuración regional. Crea un formateador con una configuración regional y opciones, luego llama a su método format() con un número.
const formatter = new Intl.NumberFormat("de-DE", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const price = 19.99;
console.log(formatter.format(price));
// Output: "19,99" (uses comma for German locale)
El mismo formateador produce diferentes resultados para diferentes configuraciones regionales.
const price = 19.99;
const usFormatter = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const deFormatter = new Intl.NumberFormat("de-DE", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
console.log(usFormatter.format(price));
// Output: "19.99"
console.log(deFormatter.format(price));
// Output: "19,99"
El separador decimal cambia automáticamente según la configuración regional.
Formateo con exactamente 2 decimales
Para mostrar exactamente 2 decimales, establece tanto minimumFractionDigits como maximumFractionDigits en 2. Esto garantiza que el resultado siempre tenga 2 decimales, rellenando con ceros cuando sea necesario y redondeando cuando el número tenga más precisión.
const formatter = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
console.log(formatter.format(5));
// Output: "5.00"
console.log(formatter.format(5.5));
// Output: "5.50"
console.log(formatter.format(5.555));
// Output: "5.56"
La opción minimumFractionDigits controla los ceros finales. Sin ella, los números con menos decimales no mostrarían los ceros.
const withoutMinimum = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 2
});
console.log(withoutMinimum.format(5));
// Output: "5"
const withMinimum = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
console.log(withMinimum.format(5));
// Output: "5.00"
Establecer ambas opciones al mismo valor garantiza decimales consistentes en todos los números.
Formateo con hasta 2 decimales
A veces quieres mostrar decimales solo cuando sea necesario, hasta un máximo de 2. Establece maximumFractionDigits en 2 y minimumFractionDigits en 0 u omítelo por completo.
const formatter = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 0,
maximumFractionDigits: 2
});
console.log(formatter.format(5));
// Output: "5"
console.log(formatter.format(5.5));
// Output: "5.5"
console.log(formatter.format(5.555));
// Output: "5.56"
Este enfoque elimina los ceros finales pero aún limita la precisión a 2 decimales. Funciona bien para mostrar mediciones o estadísticas donde los ceros finales no añaden información.
El valor predeterminado para minimumFractionDigits es 0 para el formateo de números simple, por lo que puedes omitirlo.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 2
});
console.log(formatter.format(5));
// Output: "5"
console.log(formatter.format(5.5));
// Output: "5.5"
Reutilización de formateadores para mejor rendimiento
Crear una nueva instancia de Intl.NumberFormat es relativamente costoso. Si formateas muchos números con las mismas opciones, crea el formateador una vez y reutilízalo.
const formatter = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const prices = [19.99, 29.5, 99, 149.999];
prices.forEach(price => {
console.log(formatter.format(price));
});
// Output:
// "19.99"
// "29.50"
// "99.00"
// "150.00"
Este patrón es más eficiente que crear un nuevo formateador para cada número.
Cuándo usar cada enfoque
Usa exactamente 2 decimales al mostrar precios, cantidades monetarias o cualquier valor donde los decimales tengan significado semántico. Mostrar "$5.00" en lugar de "$5" indica precisión y coincide con las expectativas del usuario para precios.
Usa hasta 2 decimales al mostrar estadísticas, medidas o valores calculados donde los ceros finales no aportan información. Mostrar "5 metros" en lugar de "5.00 metros" es más limpio y legible.
Usa toFixed() solo cuando estés seguro de que todos tus usuarios utilizan la misma convención de separador decimal, o cuando la salida no sea de cara al usuario. Para aplicaciones internacionalizadas, prefiere Intl.NumberFormat.
Usar la configuración regional preferida del usuario
En lugar de codificar una configuración regional, usa las preferencias de idioma del navegador del usuario. La propiedad navigator.language proporciona la configuración regional preferida del usuario.
const formatter = new Intl.NumberFormat(navigator.language, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const price = 19.99;
console.log(formatter.format(price));
// Output varies by user's locale
// For en-US: "19.99"
// For de-DE: "19,99"
// For fr-FR: "19,99"
También puedes pasar el array completo de navigator.languages para permitir que la API Intl seleccione la primera configuración regional compatible de las preferencias del usuario.
const formatter = new Intl.NumberFormat(navigator.languages, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
Este enfoque proporciona respaldo automático si la primera preferencia del usuario no es compatible.