JavaScript 數字格式化:最簡單的方法(千分位與貨幣)

JavaScript 數字格式化:最簡單的方法(千分位與貨幣)

前言

最近剛好有一個需求要把數字格式化成千分位或貨幣格式,剛好就寫一下這一篇該如何實現這個需求。

千分位格式化

通常我們在做一些金流或報表時,會需要將數字格式化成千分位,而方式有很多種:

1
2
3
const number = 1234567.89;
const formattedNumber = number.toLocaleString('en-US'); // "1,234,567.89"
console.log(formattedNumber); // "1,234,567.89"

這個方法會根據指定的地區格式化數字,'en-US' 代表美國格式,會使用逗號作為千分位分隔符。

但如果你想要自訂分隔符號,可以使用正則表達式:

1
2
3
4
5
6
7
function formatNumberWithCommas(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}

const number = 1234567.89;
const formattedNumber = formatNumberWithCommas(number); // "1.234.567.89"
console.log(formattedNumber); // "1.234.567.89"

這個函式會將數字轉換成字串,然後使用正則表達式在每三位數前插入指定的分隔符號(這裡用的是 .)。

但如果今天想要在數字前面加上貨幣符號,可以這樣做:

1
2
3
4
5
6
7
function formatCurrency(number, currencySymbol = '$') {
return currencySymbol + number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

const number = 1234567.89;
const formattedCurrency = formatCurrency(number, 'NT$'); // "NT$1,234,567.89"
console.log(formattedCurrency); // "NT$1,234,567.89"

其實可以發現不管是千分位或貨幣格式化,都是利用正則表達式來達成的。

如果不使用上述的方法,則是可能會改用 numeral 這個套件來處理,但…這個套件已經沒有在維護且較老舊,許多人會乾脆自己寫。

Intl.NumberFormat

傳統方法雖然可行,但不夠直覺與易維護,那…到底有沒有更符合現代 JavaScript 的寫法呢?答案是有的,那就是使用 Intl.NumberFormat

現代開發更推薦用內建的 Intl.NumberFormat,因為效能好又免安裝,下面是它的基本用法:

1
2
const formatter = new Intl.NumberFormat(locales, options);
formatter.format(number);
  • locales 用來指定地區,例如 'en-US''zh-TW' 等等。
  • options 用來指定格式化選項,例如 stylecurrencyminimumFractionDigits 等等。

Intl.NumberFormat 是一個專門用來格式化數字的 JavaScript 內建物件,可以非常方便地處理各種數字格式化需求,底下是一個範例:

1
2
3
4
5
6
7
const number = 1234567.89;
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
const formattedCurrency = formatter.format(number); // "$1,234,567.89"
console.log(formattedCurrency); // "$1,234,567.89"

你可以看到這個方法不僅可以處理千分位,還可以直接處理貨幣符號,不用再自己去寫正規表達式,而且可以根據不同的地區自動調整格式,非常方便。

如果你想要格式化成其他貨幣,只需要更改 currency 的值即可,例如:

1
2
3
4
5
6
7
const number = 1234567.89;
const formatter = new Intl.NumberFormat('ja-JP', {
style: 'currency',
currency: 'JPY',
});
const formattedCurrency = formatter.format(number); // "¥1,234,568"
console.log(formattedCurrency); // "¥1,234,568"

這樣就可以輕鬆地將數字格式化成日圓的格式。

options

options 本身還有很多其他的選項可以使用,以下是一些常用的選項:

  • style: 指定格式化的樣式
    • 'decimal': 十進位格式(預設值)
    • 'currency':貨幣格式
    • 'percent':百分比格式
  • currency: 指定貨幣的類型(例如 'USD''EUR''JPY' 等等),這個選項只有在 style 設為 'currency' 時才需要設定。
  • currencyDisplay: 指定貨幣符號的顯示方式
    • 'symbol':顯示貨幣符號(例如 $¥ 等等)
    • 'code':顯示貨幣代碼(例如 USDEURJPY 等等)
    • 'name':顯示貨幣名稱(例如 US DollarEuroJapanese Yen 等等)
  • minimumIntegerDigits: 指定整數部分的最小位數,如果不足會在前面補零。
  • minimumFractionDigits: 指定小數部分的最小位數,如果不足會在後面補零。
  • maximumFractionDigits: 指定小數部分的最大位數,如果超過會進行四捨五入。
  • minimumSignificantDigits: 指定有效數字的最小位數。
  • maximumSignificantDigits: 指定有效數字的最大位數。

範例

接下來底下我也條列一下每一個選項的範例:

style

要把數字用什麼來格式化:

1
2
3
4
5
6
7
8
9
10
11
// decimal (預設)
new Intl.NumberFormat('zh-TW', { style: 'decimal' }).format(1234567.89);
// "1,234,567.89"

// currency
new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'TWD' }).format(1234567.89);
// "$1,234,567.89"

// percent
new Intl.NumberFormat('zh-TW', { style: 'percent' }).format(0.123);
// "12%"

currency

style: 'currency' 時,指定是哪一種貨幣:

1
2
3
4
5
6
7
8
new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'USD' }).format(1234.5);
// "US$1,234.50"

new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'JPY' }).format(1234.5);
// "¥1,235" (沒有小數,因為日圓沒有小數位)

new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'EUR' }).format(1234.5);
// "€1,234.50"

currencyDisplay

決定貨幣怎麼顯示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// symbol (預設)
new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'USD', currencyDisplay: 'symbol' }).format(1234);
// "US$1,234.00"

// code
new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'USD', currencyDisplay: 'code' }).format(1234);
// "USD 1,234.00"

// name
new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'USD', currencyDisplay: 'name' }).format(1234);
// "1,234.00 美元"

// narrowSymbol (某些幣種會省略國碼)
new Intl.NumberFormat('zh-TW', { style: 'currency', currency: 'USD', currencyDisplay: 'narrowSymbol' }).format(1234);
// "$1,234.00"

Note
不同瀏覽器 / Node.js 版本 / ICU 資料 會影響結果。如果想要保證輸出 NT$,可以額外指定 currencyDisplay: ‘narrowSymbol’ 或手動處理。

minimumIntegerDigits

設定整數部分至少幾位,不足補 0:

1
2
3
4
5
6
new Intl.NumberFormat('zh-TW', { minimumIntegerDigits: 3 }).format(7);
// "007"

new Intl.NumberFormat('zh-TW', { minimumIntegerDigits: 5 }).format(123);
// "00123"

minimumFractionDigits

小數部分最少顯示幾位:

1
2
3
4
5
new Intl.NumberFormat('zh-TW', { minimumFractionDigits: 2 }).format(5);
// "5.00"

new Intl.NumberFormat('zh-TW', { minimumFractionDigits: 4 }).format(5.1);
// "5.1000"

maximumFractionDigits

小數部分最多顯示幾位(多的會四捨五入):

1
2
3
4
5
new Intl.NumberFormat('zh-TW', { maximumFractionDigits: 2 }).format(5.6789);
// "5.68"

new Intl.NumberFormat('zh-TW', { maximumFractionDigits: 0 }).format(5.9);
// "6"

minimumSignificantDigits

有效數字最少幾位,不足補 0:

1
2
3
4
5
new Intl.NumberFormat('zh-TW', { minimumSignificantDigits: 3 }).format(7);
// "7.00"

new Intl.NumberFormat('zh-TW', { minimumSignificantDigits: 5 }).format(123);
// "123.00"

maximumSignificantDigits

有效數字最多多少位,多的會四捨五入。

1
2
3
4
5
new Intl.NumberFormat('zh-TW', { maximumSignificantDigits: 3 }).format(12345);
// "12300"

new Intl.NumberFormat('zh-TW', { maximumSignificantDigits: 4 }).format(0.0012345);
// "0.001235"