【译】原生格式化JavaScript中的数字

1,180 阅读2分钟

原文:elijahmanor.com/format-js-n…

姊妹篇:【译】原生格式化JavaScript中的日期与时间

当我需要格式化 JavaScript 中的数字时,我通常使用 Number.prototype.toFixed(),寻找一个第三方库,或手动操作数字以满足我的需要。但是,对于现代浏览器,可以从 Number.prototype.toLocateString() 或者 Intl.NumberFormat 开始使用一些非常有趣的能力。以下是 caniuse.com 获取的浏览器支持情况。

说明:虽然从上图看上去支持性很不错,然而一些选项(compactDisplaycurrencySignnotationsignDisplayunitunitDisplay)在 Safari 中并不支持(见 MDN 中的表格)。还好我们可以使用一些 Form.JS 的 polyfill。

6分钟概览

视频

Number.prototype.toLocaleString()

Number.prototype.toLocaleString() 方法接受 localesoptions 两个可选参数。如果都不传,会获得浏览器的默认语言环境。在以下各节中,我们将重点介绍 options 参数。

const number = 12345.6789;

console.log(number.toLocaleString());
// 12,345.679 (defaults to the "en-US" locale in my case)

console.log(number.toLocaleString('de-DE'));
// 12.345,679

货币格式

格式化数字固然很好,但是怎么处理金钱呢?这就是第二个可选参数 options 起作用的场景。如果你提供 {style: "currency"} 属性和有效 currency (ISO 4217 货币代码),那么你将获得精美且支持语言环境的货币格式化结果!

注意:没有默认的 currency 代码,因此不提供会出现错误。

const number = 12345.6789;

console.log(
  number.toLocaleString('en-US', {
    style: 'currency',
    currency: 'USD',
  }),
);
// $12,345.68

console.log(
  number.toLocaleString('de-DE', {
    style: 'currency',
    currency: 'EUR',
  }),
);
// 12.345,68 €

console.log(
  number.toLocaleString('ja-JP', {
    style: 'currency',
    currency: 'JPY',
  }),
);
// ¥12,346
Significant Digits
Sometimes you want to control how many digits are significant in a number. You might think of this as Frontend Estimation. You can provide a minimumSignificantDigits (defaults to 1) or a maximumSignificantDigits (defaults to 21).

const number = 12345.6789;

console.log(
  number.toLocaleString('en-US', {
    maximumSignificantDigits: 1,
  }),
);
// 10,000

console.log(
  number.toLocaleString('fr-FR', {
    maximumSignificantDigits: 3,
  }),
);
// 12 300

单位支持

单位支持是那种我本来没有期待成为一个功能点,但是有的话非常酷。你可以混合搭配语言环境及度量单位。你可以从 ECMAScript 规范 中找到可能的单位的完整列表。还可以提供 longshort(默认),或 narrow 来控制显示单位的精细程度。

注意:这是 Safari 不支持的功能之一。另外,unit 没有默认值,因此如果 style 设置为 unit,则必须提供一个 unit 值。

const number = 12345.6789;

console.log(
  number.toLocaleString('en-US', {
    style: 'unit',
    unit: 'mile-per-hour',
  }),
);
// 12,345.679 mph

console.log(
  number.toLocaleString('fr-FR', {
    style: 'unit',
    unit: 'liter',
    unitDisplay: 'long',
  }),
);
// 12 345,679 litres

简写

当我发现此功能存在时,我感到很有趣。不久之前,我需要类似的简写形式。我最终在网上找到了一小段代码来完成这项工作,但是现在我知道我可以使用{notation:"compact"}!它还需要一个可选的 compactDisplay,可以将其设置为 short(默认)或 long

注意:这是 Safari 不支持的功能之一。

const number = 12345.6789;

console.log(
  number.toLocaleString('en-US', {
    notation: 'compact',
    compactDisplay: 'short',
  }),
);
// 12K

console.log(
  number.toLocaleString('en-US', {
    notation: 'compact',
    compactDisplay: 'long',
  }),
);
// 12 thousand

百分比

拥有百分比支持可能并不会让您感到十分惊讶,但是这个功能很方便,因为它具有本地适配(就像所有其他选项一样)。你还可以提供其他选项,例如 minimumFractionDigits(默认为 0,对于货币默认为2),或 maximumFractionDigits 来控制要使用的小数位数。

const number = 0.1234;

console.log(
  number.toLocaleString('en-US', {
    style: 'percent',
    minimumFractionDigits: 2,
  }),
);
// 12.34%

会计

我通常不会在括号中显示负货币,但显然,这是进行大量会计处理的人员的常用方法。我可能不会使用它,但是很高兴知道这是我可以选择的选项。

注意:这是 Safari 不支持的功能之一。

const number = -123.456;

console.log(
  number.toLocaleString('en-US', {
    style: 'currency',
    currency: 'USD',
    currencySign: 'accounting',
    signDisplay: 'always',
  }),
);
// ($123.46)

Intl.NumberFormat

除了使用 Number.prototype.toLocaleString() 之外,你还可以使用Intl.NumberFormat 构造函数,然后调用 format 方法来格式化数字。 但是,这可能会造成混乱,并可能使你怀疑应该使用哪种技术。 如果发现自己需要使用相同的语言环境和相同的选项来一次又一次地格式化许多数字,则出于性能方面的考虑,最好使用Intl.NumberFormat

“格式化大量数字时,最好创建一个 NumberFormat 对象并使用其 NumberFormat.format 属性提供的功能。”--Number.prototype.toLocaleString()

const numberFormat = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'mile-per-hour',
});

console.log(numberFormat.format(12345.6789));
// 12,345.679 mph

console.log(numberFormat.format(2345.67891));
// 2,345.679 mph