JavaScriptで数値を小数点以下2桁にフォーマットする方法

価格、パーセンテージ、測定値のために数値を正確に小数点以下2桁で表示する

はじめに

多くのアプリケーションでは、固定された小数点以下の桁数で数値を表示する必要があります。価格は通常$19.99のように小数点以下2桁で表示されます。パーセンテージは45.50%のように表示されることが多いです。測定値は読みやすさのために3.14メートルのように一貫した小数点以下の桁数を使用します。

小数点以下の桁数を制御することで、アプリケーション全体で視覚的な一貫性を確保できます。明示的なフォーマットがなければ、JavaScriptは実際の値に基づいて様々な小数点以下の桁数で数値を表示します。数値5は「5」として表示される一方、5.5は「5.5」として表示され、一貫性のない配置や外観を生み出します。

このレッスンでは、異なるロケールの慣習を尊重しながら、数値を正確に小数点以下2桁、または最大2桁までフォーマットする方法を紹介します。

基本的なフォーマットにtoFixed()を使用する

toFixed()メソッドは、数値を指定された小数点以下の桁数を持つ文字列に変換します。引数として小数点以下の桁数を渡します。

const price = 19.9;
const formatted = price.toFixed(2);
console.log(formatted);
// 出力: "19.90"

このメソッドは常に正確に2桁の小数点以下を表示します。数値の小数点以下の桁数が少ない場合、toFixed()はゼロで埋めます。桁数が多い場合は、2桁に丸めます。

const examples = [5, 5.5, 5.555, 5.999];

examples.forEach(num => {
  console.log(num.toFixed(2));
});
// 出力:
// "5.00"
// "5.50"
// "5.56"
// "6.00"

toFixed()メソッドは数値ではなく文字列を返します。これは意図的なものです。なぜなら、末尾のゼロは表示上意味がありますが、数値として返された場合は失われてしまうからです。

toFixed()のロケールに関する問題

toFixed()メソッドは、ユーザーのロケールに関係なく、常にピリオドを小数点区切り文字として使用します。多くの国ではピリオドの代わりにカンマを小数点区切り文字として使用しています。

const price = 19.99;
console.log(price.toFixed(2));
// 出力: "19.99" (常にピリオドを使用)

ドイツ、フランス、スペインなど多くの国のユーザーにとって、これは正しく見えません。彼らは「19.99」ではなく「19,99」を期待しています。toFixed()メソッドはロケールに適した出力を生成できません。

異なるロケールに対して数値を正しくフォーマットするには、Intl.NumberFormat APIを使用してください。

ロケールに対応したフォーマットのためのIntl.NumberFormatの使用

Intl.NumberFormat APIはロケールの規則に従って数値をフォーマットします。ロケールとオプションを指定してフォーマッターを作成し、そのformat()メソッドに数値を渡して呼び出します。

const formatter = new Intl.NumberFormat("de-DE", {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

const price = 19.99;
console.log(formatter.format(price));
// 出力: "19,99" (ドイツロケールではカンマを使用)

同じフォーマッターでも、異なるロケールでは異なる出力が生成されます。

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));
// 出力: "19.99"

console.log(deFormatter.format(price));
// 出力: "19,99"

小数点の区切り文字はロケールに基づいて自動的に変更されます。

小数点以下2桁で正確にフォーマットする

小数点以下2桁で表示するには、minimumFractionDigitsmaximumFractionDigitsの両方を2に設定します。これにより、出力は常に小数点以下2桁になり、必要に応じてゼロで埋められ、より精度の高い数値は丸められます。

const formatter = new Intl.NumberFormat("en-US", {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

console.log(formatter.format(5));
// 出力: "5.00"

console.log(formatter.format(5.5));
// 出力: "5.50"

console.log(formatter.format(5.555));
// 出力: "5.56"

minimumFractionDigitsオプションは末尾のゼロを制御します。これがなければ、小数点以下の桁数が少ない数値ではゼロが表示されません。

const withoutMinimum = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 2
});

console.log(withoutMinimum.format(5));
// 出力: "5"

const withMinimum = new Intl.NumberFormat("en-US", {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

console.log(withMinimum.format(5));
// 出力: "5.00"

両方のオプションを同じ値に設定することで、すべての数値で一貫した小数点以下の桁数が保証されます。

最大2桁までの小数点でフォーマットする

必要な場合にのみ小数点以下を表示し、最大で2桁までにしたい場合があります。maximumFractionDigitsを2に設定し、minimumFractionDigitsを0に設定するか、完全に省略します。

const formatter = new Intl.NumberFormat("en-US", {
  minimumFractionDigits: 0,
  maximumFractionDigits: 2
});

console.log(formatter.format(5));
// 出力: "5"

console.log(formatter.format(5.5));
// 出力: "5.5"

console.log(formatter.format(5.555));
// 出力: "5.56"

このアプローチでは末尾のゼロは削除されますが、精度は小数点以下2桁に制限されます。末尾のゼロが情報を追加しない測定値や統計を表示する場合に適しています。

通常の数値フォーマットではminimumFractionDigitsのデフォルト値は0なので、省略することができます。

const formatter = new Intl.NumberFormat("en-US", {
  maximumFractionDigits: 2
});

console.log(formatter.format(5));
// 出力: "5"

console.log(formatter.format(5.5));
// 出力: "5.5"

パフォーマンス向上のためのフォーマッターの再利用

新しいIntl.NumberFormatインスタンスの作成は比較的コストがかかります。同じオプションで多くの数値をフォーマットする場合は、フォーマッターを一度作成して再利用しましょう。

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));
});
// 出力:
// "19.99"
// "29.50"
// "99.00"
// "150.00"

このパターンは、数値ごとに新しいフォーマッターを作成するよりも効率的です。

各アプローチの使い分け

価格、通貨金額、または小数点以下に意味がある値を表示する場合は、正確に小数点以下2桁を使用してください。「$5」ではなく「$5.00」と表示することで、精度を示し、価格に対するユーザーの期待に応えます。

統計、測定値、または末尾のゼロが情報を追加しない計算値を表示する場合は、最大2桁の小数点を使用してください。「5.00メートル」ではなく「5メートル」と表示する方が、より簡潔で読みやすくなります。

toFixed()は、ユーザーが全員同じ小数点区切り文字の規則を使用していることが確実な場合、またはユーザー向けでない出力の場合にのみ使用してください。国際化されたアプリケーションでは、Intl.NumberFormatを優先してください。

ユーザーの優先ロケールの使用

ロケールをハードコーディングする代わりに、ユーザーのブラウザ言語設定を使用してください。navigator.languageプロパティはユーザーの優先ロケールを提供します。

const formatter = new Intl.NumberFormat(navigator.language, {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

const price = 19.99;
console.log(formatter.format(price));
// 出力はユーザーのロケールによって異なります
// en-USの場合: "19.99"
// de-DEの場合: "19,99"
// fr-FRの場合: "19,99"

また、navigator.languages配列全体を渡して、ユーザーの設定から最初にサポートされているロケールをIntl APIに選択させることもできます。

const formatter = new Intl.NumberFormat(navigator.languages, {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

このアプローチでは、ユーザーの最初の設定がサポートされていない場合に自動的にフォールバックが提供されます。