How to format numbers with commas as thousands separators in JavaScript?
I’m trying to format integers in JavaScript with commas as thousands separators. For example, I want to convert the number 1234567 to “1,234,567”. Here’s my current implementation:
function numberWithCommas(x) {
x = x.toString();
var pattern = /(-?\d+)(\d{3})/;
while (pattern.test(x))
x = x.replace(pattern, "$1,$2");
return x;
}
console.log(numberWithCommas(1000))
Is there a simpler or more elegant way to achieve this? It would be beneficial if the solution works with floating-point numbers as well, but that’s not a requirement. The solution doesn’t need to be locale-specific for choosing between periods and commas.
JavaScript offers several built-in methods for formatting numbers with commas as thousands separators. The most modern and elegant approach is using Intl.NumberFormat or toLocaleString(), which provide native browser support without manual string manipulation. For integers like 1234567, you can simply use 1234567.toLocaleString() to get “1,234,567”.
Contents
- Built-in Methods
- Regular Expression Approach
- Manual String Manipulation
- Comparison of Methods
- Handling Floating-Point Numbers
- Browser Support and Alternatives
- Performance Considerations
Built-in Methods
Using toLocaleString()
The simplest and most elegant solution is using the built-in toLocaleString() method:
const number = 1234567;
const formatted = number.toLocaleString();
console.log(formatted); // "1,234,567"
This method automatically handles thousands separators and works with both integers and floating-point numbers:
console.log(1234567.89.toLocaleString()); // "1,234,567.89"
console.log(1000.toLocaleString()); // "1,000"
Using Intl.NumberFormat
For more control and better performance in loops, use Intl.NumberFormat:
const formatter = new Intl.NumberFormat();
const formatted = formatter.format(1234567);
console.log(formatted); // "1,234,567"
You can create a reusable formatter:
// Create a reusable formatter
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
// Use it multiple times
console.log(currencyFormatter.format(1234567)); // "$1,234,567.00"
Regular Expression Approach
Your current implementation using regular expressions is functional but can be simplified:
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
console.log(numberWithCommas(1234567)); // "1,234,567"
This regex pattern \B(?=(\d{3})+(?!\d)) uses a positive lookahead to find positions that are:
\B- Not at a word boundary (ensures we don’t add commas at the start)(?=(\d{3})+)- Followed by groups of exactly 3 digits(?!\d)- Not followed by any more digits (ensures we don’t add trailing commas)
Manual String Manipulation
For environments without Intl support or when you need maximum control:
function formatNumberWithCommas(num) {
const parts = num.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
}
console.log(formatNumberWithCommas(1234567)); // "1,234,567"
console.log(formatNumberWithCommas(1234567.89)); // "1,234,567.89"
Comparison of Methods
| Method | Performance | Browser Support | Flexibility | Code Complexity |
|---|---|---|---|---|
toLocaleString() |
Good | All modern browsers | High | Very simple |
Intl.NumberFormat |
Excellent (cached) | All modern browsers | Very high | Simple |
| Regular Expression | Moderate | All browsers | Medium | Moderate |
| Manual parsing | Good | All browsers | Low | Simple |
Handling Floating-Point Numbers
All built-in methods automatically handle decimal points:
const number = 1234567.8912;
// Using toLocaleString
console.log(number.toLocaleString()); // "1,234,567.891"
// Using Intl.NumberFormat
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 4
});
console.log(formatter.format(number)); // "1,234,567.8912"
For your specific needs, you can create a simple wrapper:
function formatNumber(num) {
return num.toLocaleString();
}
// Works with both integers and floats
console.log(formatNumber(1234567)); // "1,234,567"
console.log(formatNumber(1234567.89)); // "1,234,567.89"
Browser Support and Alternatives
Modern Browsers (Chrome, Firefox, Safari, Edge)
All modern browsers fully support Intl.NumberFormat and toLocaleString() with excellent performance.
Legacy Browsers (Internet Explorer)
For older browsers, you can use a polyfill or fall back to your regex approach:
if (!window.Intl) {
// Fallback for older browsers
function formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
} else {
// Modern approach
function formatNumber(num) {
return num.toLocaleString();
}
}
Library Solutions
For advanced formatting needs, consider libraries like:
Performance Considerations
For formatting large numbers of values, Intl.NumberFormat is most efficient when cached:
// Cache formatter for better performance in loops
const numberFormatter = new Intl.NumberFormat();
function formatManyNumbers(numbers) {
return numbers.map(num => numberFormatter.format(num));
}
// Much faster than calling toLocaleString() each time
const largeArray = Array.from({length: 1000}, (_, i) => i * 1000 + 123);
const formatted = formatManyNumbers(largeArray);
Conclusion
For your use case, the simplest and most elegant solution is to use toLocaleString():
function numberWithCommas(x) {
return x.toLocaleString();
}
console.log(numberWithCommas(1234567)); // "1,234,567"
Key takeaways:
- Built-in methods are preferred:
toLocaleString()andIntl.NumberFormatare the most reliable and maintainable solutions - Performance matters: For bulk operations, cache
Intl.NumberFormatinstances - Compatibility: Modern browsers handle all these methods excellently
- Simplicity beats complexity: Your regex approach works but isn’t as clean as built-in solutions
- Flexibility: Built-in methods automatically handle both integers and floats
For most applications, toLocaleString() provides the perfect balance of simplicity and functionality. If you need more control over formatting options or are working with very large datasets, Intl.NumberFormat offers better performance and customization.