Intl.NumberFormat
It knows about currencies, locales, units and compact notation, and it's faster than the string concatenation it replaces.
I still see this in checkout code all the time:
'$' + (cents / 100).toFixed(2)
And it’s fine right up until the store sells to somebody who writes 1.234,56, or the currency is one of the ones with no minor unit, or a total needs to say US$ instead of $ because the page also shows Canadian dollars. Many such cases.
Or you can let the browser handle it:
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(1234.5);
// "$1,234.50"
Swap the locale and the rest follows: the separators, the symbol position, the spacing. You don’t have to know any of the rules. It even knows that Japanese yen has no decimal places and Kuwaiti dinar has three.
It also does two other things I reach for:
new Intl.NumberFormat('en', { notation: 'compact' }).format(48291);
// "48K"
new Intl.NumberFormat('en', { style: 'unit', unit: 'megabyte' }).format(4.2);
// "4.2 MB"
There’s one performance note worth knowing. Constructing the formatter is the expensive part, not calling it. If you’re formatting a table of 500 prices, build one formatter outside the loop. Do it that way and it’s comfortably faster than the string work it replaces, which is probably the opposite of what anybody expects.
Intl.RelativeTimeFormat and Intl.PluralRules are in the same family. They solve the two other problems that practically everybody hand-rolls.