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);
// Output: "19.90"

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

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"

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

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

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

const price = 19.99;
console.log(price.toFixed(2));
// Output: "19.99" (always uses period)

ドイツ、フランス、スペイン、その他多くの国のユーザーにとって、これは正しく見えません。彼らは「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));
// Output: "19,99" (uses comma for German locale)

同じフォーマッターでも、異なるロケールに対して異なる出力を生成します。

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"

小数点記号は、ロケールに基づいて自動的に変更されます。

小数点以下2桁でのフォーマット

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

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"

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

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"

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

小数点以下最大2桁でのフォーマット

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

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"

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

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

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"

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

新しい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));
});
// Output:
// "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));
// Output varies by user's locale
// For en-US: "19.99"
// For de-DE: "19,99"
// For fr-FR: "19,99"

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

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

このアプローチにより、ユーザーの第一希望がサポートされていない場合に自動的にフォールバックが提供されます。