大家好,我是CC,在这里欢迎大家的到来~
开场
书接上文,Intl 下的 Segmenter 对象可以实现对文本的分割,Collator 对象可以处理字符串的比较,除此之外,还有数字格式化、日期格式化等其他功能。
这篇文章先来看看数字格式化,现在来理论加实践一下。
数字格式化
Intl.NumberFormat使数字在特定语言环境下格式化。
配置项
为了方便阅读,属性列表根据用途划分为多个部分,包括区域选项、样式选项、数字选项和其他选项。
区域选项
- localeMatcher
-
- 使用的区域匹配算法,可能的值包括:
- 默认值为 best fit,还有 lookup
- numberingSystem
-
- 数字格式化的数字系统,像阿拉伯数字 arab、简体中文数字 hans、无衬线数字 mathsans
- 默认值取决于区域
- 同 locales 的 Unicode 扩展键 nu 设置,但优先级高于他
样式选项
- style
-
- 使用的格式化样式,可选的值包括:
- decimal: 普通数字格式化
- currency: 货币格式化
- percent: 百分比格式化
- unit: 单位格式化
- 默认值是 decimal
- currency
-
- 货币格式化中使用的货币,像美元 USD、欧元 EUR 和人民币 CNY。
- 没有默认值,style 为 currency 时必须提供,内容会被转换为大写。
- currencyDisplay
-
- 货币格式化中如何显示货币,可选的值包括:
- code: 使用 ISO 货币代码
- symbol: 使用本地化货币符号
- narrowSymbol: 使用窄格式符号,像 <math xmlns="http://www.w3.org/1998/Math/MathML"> 100 而不是 U S 100 而不是 US </math>100而不是US100
- name: 使用本地化货币名称,像 dollar
- currencySign
-
- 使用括号将数字括起来,而不是添加负号,可选的值包括:
- standard: 默认值
- accounting: 会计
- unit
-
- 格式化的单位
- style 为 unit 时必填
- unitDisplay
-
- unit 格式化时使用的格式化风格,可选的值包括:
- short: 默认值,例如 16 l
- narrow: 例如 16l
- long: 例如 16 litres
数字选项,由 Intl.PluralRules 支持
- minimumIntegerDigits
-
- 最小整数位数,默认值为 1,范围是 1~21
- 若实际整数位数不足会在左侧用 0 补足,比如对于数字 5 该值设置为 3 则显示为"005"
- minimumFractionDigits
-
- 小数部分的最小位数,范围是 0~100
- 若小数位数不足时会在右侧补 0,超过时会按四舍五入截断
- 默认值对于普通数字和百分比是 0,对于 currency 是 2(ISO 4217 标准小数位数)
- maximumFractionDigits
-
- 小数部分的最大位数,范围是 0~100
- 若小数位数不足时会在右侧补 0,超过时会按四舍五入截断
- 默认值对于普通数字和百分比是 3,对于 currency 是 2(ISO 4217 标准小数位数)
- minimumSignificanntDigits
-
- 最小有效数字,默认值为 1。范围是 1~21。
- 优先级高于 minimumFractionDigits
- maximumSignificanntDigits
-
- 最大有效数字,默认值为 21。范围是 1~21。
- 优先级高于 maximumFractionDigits
- roundingPriority
-
- 当同时使用 FractionDigits 和 SignificantDigits 时指定如何解决四舍五入冲突,可选的值包括:
- auto: 默认值,使用有效数字属性
- morePrecision: 使用精度更高的属性
- lessPrecision: 使用精度更低的属性
- auto 属性会在 natation 为 compact 时且未设置任何四个 FractionDigits/SignificantDigits 时会被设置为 morePrecision
- 除 auto 属性以外的值会根据 maximumSignificanntDigits 和 maximumFractionDigits 计算出更高精度,忽略最小小数位和有效数字位
- roundingIncrement
-
- 相对于计算出的舍入单位的舍入增量
- 默认值为 1,其他值包括 1、2、5、10、20、25、50、100、200、250、500、1000、2000、5000
- 不能与有效数字位舍入或任何 roundingPriority(除了 auto) 混合使用
- roundingMode
-
- 对小数进行舍入,可选的值包括:
- ceil: 向正无穷舍入,正数向上,负数"向正"
- floor: 向负无穷舍入,正数向下,负数"向负"
- expand: 四舍五入远离 0,绝对值增大
- trunc: 四舍五入朝向 0,绝对值减小
- halfCeil: 趋向于正无穷舍入,包括半值
- halfFloor: 趋向于负无穷舍入,包括半值
- halfExpand: 默认值,半值远离 0 舍入
- halfTrunc: 向 0 取整,包括半值
- halfEven: 半值向最接近的偶数整数舍入,常用于统计,减少片差
- trailingZeroDisplay
-
- 整数末尾 0 的显示策略,可选的值包括:
- auto: 默认值,根据 minimumFractionDigits 和 minimumSignificanntDigits 保持末尾 0
- stripIfInteger: 如果小数部分全为 0 则删除小数部分,如果小数部分有任何非零数则与 auto 相同
其他选项
- notation
-
- 数字的显示格式,可选的值包括:
- standard: 默认值,纯数字格式
- scientific: 返回格式化数字的数量级
- engineering: 返回能被 3 整除的 10 的指数
- compact: 表示指数的字符串,默认使用 short 形式
- compactDisplay
-
- 仅当 notation 为 compact 时使用,可选的值包括:
- short: 默认值
- long
- useGrouping
-
- 是否使用分组分隔符,像千位分隔符或者千/十万/千万分隔符,可选的值包括:
- always: 即使 locale 偏好不同也展示分组分隔符
- auto: 根据 locale 偏好显示分组分隔符,也取决于货币
- min2: 当一组数字至少有 2 位数字时显示分组分隔符
- true: 同 always
- false: 不展示分组分隔符
- 当 notation 为 compact 时默认值为 min2,否则默认值为 auto
- 字符串 true 和 false 会被转化为默认值
- signDisplay
-
- 何时显示数字符号,可选的值包括:
- auto: 默认值
- always: 总是显示
- exceptZero: 正数和负数显示符号,但 0 不显示
- negative: 仅显示负数的符号,不包括负零
- never: 从不展示
格式化
format()方法会基于区域和格式化选项进行数字格式化。支持数字、大数和字符串。
数字可能因为太大或太小而丢失精度
javascript
const numberFormat = new Intl.NumberFormat("en-US");
console.log(numberFormat.format(987654321987654321));
// 987,654,321,987,654,300
但是使用大数就不会有问题
javascript
const numberFormat = new Intl.NumberFormat("en-US");
console.log(numberFormat.format(987654321987654321n));
// 987,654,321,987,654,321
字符串也不会丢失精度
javascript
const numberFormat = new Intl.NumberFormat("en-US");
console.log(numberFormat.format("987654321987654321"));
// 987,654,321,987,654,321
使用指数表示
javascript
const numberFormat = new Intl.NumberFormat("en-US");
const bigNum = 987654321987654321n;
console.log(numberFormat.format(`${bigNum}E-6`));
// 987,654,321,987.654
格式化分割成多部分
formatToParts()将会返回一个对象数组,包含格式化后的每一部分,适合用来自定义字符串格式化。
javascript
const number = 3500;
const formatter = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR",
});
console.log(formatter.format(number));
// "3.500,00 €"
console.log(formatter.formatToParts(number));
// [
// { type: "integer", value: "3" },
// { type: "group", value: "." },
// { type: "integer", value: "500" },
// { type: "decimal", value: "," },
// { type: "fraction", value: "00" },
// { type: "literal", value: " " },
// { type: "currency", value: "€" },
// ];
格式化数字范围
formatRange()返回一个字符串表示数字范围格式化后的内容。
javascript
const nf = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0,
});
console.log(nf.formatRange(3, 5));
// "$3 -- $5"
如果开始值和结束值四舍五入值相同或者完全相同 时则会添加近似等于符号。
javascript
console.log(nf.formatRange(2.9, 3.1));
// "~$3"
格式化数字范围分割成多部分
formatRangeToParts()返回一个对象数组,包含格式化后的每一部分,适合用来自定义数字字符串的格式化范围。
javascript
const startRange = 3500;
const endRange = 9500;
const formatter = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR",
});
console.log(formatter.formatRange(startRange, endRange));
// "3.500,00--9.500,00 €"
console.log(formatter.formatRangeToParts(startRange, endRange));
// [
// { type: "integer", value: "3", source: "startRange" },
// { type: "group", value: ".", source: "startRange" },
// { type: "integer", value: "500", source: "startRange" },
// { type: "decimal", value: ",", source: "startRange" },
// { type: "fraction", value: "00", source: "startRange" },
// { type: "literal", value: "--", source: "shared" },
// { type: "integer", value: "9", source: "endRange" },
// { type: "group", value: ".", source: "endRange" },
// { type: "integer", value: "500", source: "endRange" },
// { type: "decimal", value: ",", source: "endRange" },
// { type: "fraction", value: "00", source: "endRange" },
// { type: "literal", value: " ", source: "shared" },
// { type: "currency", value: "€", source: "shared" },
// ]
获取配置项
javascript
const de = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "USD",
maximumFractionDigits: 2,
roundingIncrement: 5,
roundingMode: "halfCeil",
});
const usedOptions = de.resolvedOptions();
console.log(usedOptions.locale); // "de-DE"
console.log(usedOptions.numberingSystem); // "latn"
console.log(usedOptions.compactDisplay); // undefined ("notation" not set to "compact")
console.log(usedOptions.currency); // "USD"
console.log(usedOptions.currencyDisplay); // "symbol"
console.log(usedOptions.currencySign); // "standard"
console.log(usedOptions.minimumIntegerDigits); // 1
console.log(usedOptions.minimumFractionDigits); // 2
console.log(usedOptions.maximumFractionDigits); // 2
console.log(usedOptions.minimumSignificantDigits); // undefined (maximumFractionDigits is set)
console.log(usedOptions.maximumSignificantDigits); // undefined (maximumFractionDigits is set)
console.log(usedOptions.notation); // "standard"
console.log(usedOptions.roundingIncrement); // 5
console.log(usedOptions.roundingMode); // halfCeil
console.log(usedOptions.roundingPriority); // auto
console.log(usedOptions.signDisplay); // "auto"
console.log(usedOptions.style); // "currency"
console.log(usedOptions.trailingZeroDisplay); // auto
console.log(usedOptions.useGrouping); // auto
判断返回支持的 locale
在给定的 locales 数组中判断出 NumberFormat 支持的 locales。但是可能每个浏览器支持的不大一样。
javascript
const locales = ["ban", "id-u-co-pinyin", "de-ID"];
const options = { localeMatcher: "lookup" };
console.log(Intl.NumberFormat.supportedLocalesOf(locales, options));
// ["id-u-co-pinyin", "de-ID"]
总结
Intl.NumberFormat用于根据语言和地区格式化数字内容,像把数字格式化为货币、百分比或带单位的本地化字符串,精确控制数字的小数位数、有效数字和整数部分的最小位数,设置丰富的舍入模式像四舍五入、向零舍入或银行家舍入法这些场景下都十分适用。