JavaScript 中 Intl.NumberFormat 的实战用法:从千分位到货币与单位格式化
最近在一个后台管理项目的财务模块里,需要在页面上展示多币种金额、百分比、文件大小和紧凑数字(比如 12.3K、1.2M),后端返回的都是原始数值,前端要按不同地区用户的习惯做本地化格式化。以前团队里习惯手写 `toFixed`、字符串截取加符号,结果遇到欧元符号位置、印度数字分组(1,00,000 这种)、阿拉伯语环境下的数字方向时,代码里全是判断分支,维护起来很痛苦。后来把这类需求统一交给 `Intl.NumberFormat`,大部分逻辑都收敛成配置项了。这篇文章整理一下我在实际项目里用到的几种配置方式,包括普通数字分组、货币格式、百分比、紧凑计数,以及如何通过 `formatToParts` 做更细粒度的渲染控制。 ## 基础用法与常见参数 `Intl.NumberFormat` 是 ECMAScript 国际化 API 的一部分,现代浏览器和 Node.js(完整 ICU 版本)都支持。最基本的用法就是传入语言标签,然后调用 `format`: ```js const nf = new Intl.NumberFormat('zh-CN'); nf.format(1234567.89); // "1,234,567.89" const nfEn = new Intl.NumberFormat('en-US'); nfEn.format(1234567.89); // "1,234,567.89" const nfDe = new Intl.NumberFormat('de-DE'); nfDe.format(1234567.89); // "1.234.567,89" ``` 德语环境里千分位和小数点正好和英语相反,如果自己拼字符串很容易漏掉这种差异。`Intl.NumberFormat` 内部根据 CLDR 数据做处理,不需要我们维护规则。 几个常用的选项: - `style`:`decimal`(默认)、`currency`、`percent`、`unit` - `currency`:当 `style` 为 `currency` 时必填,ISO 4217 代码,比如 `CNY`、`USD`、`EUR` - `currencyDisplay`:`symbol`、`code`、`name`,控制显示符号还是文字 - `useGrouping`:是否启用千分位分组 - `minimumFractionDigits` / `maximumFractionDigits`:控制小数位数 - `notation`:`standard`、`scientific`、`engineering`、`compact` ## 货币格式化里容易踩的坑 做跨境电商时遇到过一个问题:同一个商品价格,美国用户看到 `$1,299.00`,法国用户看到 `1 299,00 €`,日本用户看到 `¥1,299`。如果按字符串拼接,需要维护每个币种的小数位数和符号位置。用 `Intl` 直接写: ```js function formatCurrency(value, currency, locale) { return new Intl.NumberFormat(locale, { style: 'currency', currency, // 有些业务要求固定两位小数,避免 ¥1,299 这种没有小数位的展示 minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(value); } formatCurrency(1299, 'USD', 'en-US'); // "$1,299.00" formatCurrency(1299, 'EUR', 'fr-FR'); // "1 299,00 €" formatCurrency(1299, 'JPY', 'ja-JP'); // "¥1,299.00" ``` 注意日元本身在 CLDR 里默认没有小数位,如果业务强制两位,需要通过 `minimumFractionDigits` 覆盖。另外 `currencyDisplay` 设成 `name` 时会输出“1,299.00 美元”这样的文字,在需要无障碍朗读的场景下有用。 ## 百分比和紧凑计数 百分比场景是数据看板里最常见的,比如增长率、转化率。后端通常返回 0.1234 这样的比例,前端要显示成 12.34%。 ```js const percentFmt = new Intl.NumberFormat('zh-CN', { style: 'percent', minimumFractionDigits: 1, maximumFractionDigits: 2 }); percentFmt.format(0.1234); // "12.34%" percentFmt.format(0.5); // "50.0%" ``` `style: 'percent'` 会自动把数值乘以 100 并追加百分号,不需要自己算。 紧凑计数适合展示点赞数、阅读量、文件大小这类数字。`notation: 'compact'` 会按语言习惯输出 K、M、B 或者中文的“万”“亿”: ```js const compactZh = new Intl.NumberFormat('zh-CN', { notation: 'compact', compactDisplay: 'short' }); compactZh.format(12345); // "1.2万" compactZh.format(123456789); // "1.2亿" const compactEn = new Intl.NumberFormat('en-US', { notation: 'compact' }); compactEn.format(12345); // "12K" ``` 中文环境下 `compactDisplay: 'long'` 会输出“1.2万”这种形式,`short` 在某些实现里会输出“1.2万”也可能输出“1.2万”,具体看 ICU 版本。实际项目里如果对展示文案有严格 UI 要求,建议用 `formatToParts` 拿到数字和单位分别处理。 ## 用 formatToParts 做细粒度控制 有时候设计稿要求数字用一种字体、单位用另一种字体,或者要把单位变成可点击的 tooltip。`format` 返回的是完整字符串,拿不到分段信息,这时候用 `formatToParts`: ```js const fmt = new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY', currencyDisplay: 'symbol' }); console.log(fmt.formatToParts(1234.5)); // [ // { type: 'currency', value: '¥' }, // { type: 'integer', value: '1' }, // { type: 'group', value: ',' }, // { type: 'integer', value: '234' }, // { type: 'decimal', value: '.' }, // { type: 'fraction', value: '5' } // ] ``` 在 Vue 或 React 里可以这样渲染: ```jsx function CurrencyText({ value, currency, locale }) { const parts = new Intl.NumberFormat(locale, { style: 'currency', currency }).formatToParts(value); return ( {parts.map((part, i) => ( {part.value} ))} ); } ``` 配合 CSS 就能给 `.part-currency` 单独设颜色或边距,不用去拆字符串。 ## 单位格式化的实际场景 文件大小、距离、温度这些带单位的数值,用 `style: 'unit'` 比手动拼 `MB`、`km` 更省事: ```js const byteFmt = new Intl.NumberFormat('zh-CN', { style: 'unit', unit: 'megabyte', unitDisplay: 'short' }); byteFmt.format(2.5); // "2.5 MB" const kmFmt = new Intl.NumberFormat('en-US', { style: 'unit', unit: 'kilometer', unitDisplay: 'long' }); kmFmt.format(5); // "5 kilometers" ``` `unit` 支持的单位列表在 ECMA-402 规范里有定义,常见的 `byte`、`kilobyte`、`megabyte`、`gigabyte`、`second`、`minute`、`hour`、`celsius`、`fahrenheit`、`kilometer`、`mile` 都可用。 不过要注意,`Intl.NumberFormat` 的 `unit` 并不会自动做单位换算。2.5 MB 传入 `megabyte` 就是 2.5 MB,不会帮你从字节转过来。换算逻辑还是得自己写,只是把显示部分交给它。 ## 性能与缓存 `new Intl.NumberFormat` 的构造过程涉及加载 locale 数据,虽然现代浏览器做了缓存,但在列表里对每个单元格都 new 一次仍然不划算。常见的做法是按 `locale + options` 做 key 缓存 formatter 实例: ```js const cache = new Map(); function getFormatter(locale, options) { const key = locale + JSON.stringify(options); if (!cache.has(key)) { cache.set(key, new Intl.NumberFormat(locale, options)); } return cache.get(key); } ``` 在表格里渲染几百行时,这个缓存能省掉不少重复构造。另一个细节是 `Intl.NumberFormat` 的 options 对象顺序会影响 `JSON.stringify` 的结果,如果动态拼 options,最好保证字段顺序稳定,否则缓存命中率会下降。 ## Node.js 环境下的注意点 Node.js 从 13 开始默认带 full-icu,但有些 Docker 镜像为了减小体积会裁剪掉 ICU 数据,导致 `Intl.NumberFormat` 输出英文格式甚至报错。线上服务如果做服务端渲染,构建镜像时确认 `node -p "process.config.variables.icu_small"` 是 false,或者直接用官方 node 镜像。 ```js // 检查当前 Node 的 ICU 支持情况 console.log(Intl.NumberFormat.supportedLocalesOf(['zh-CN', 'de-DE', 'ar-EG'])); ``` 如果返回数组里缺少你需要的 locale,说明 ICU 数据不全,需要换构建方式或安装 `full-icu` 包。 `Intl.NumberFormat` 不能覆盖所有格式化需求,比如自定义的“前 N 位用大字号、后 M 位用小字号”这种设计稿,还是得靠 `formatToParts` 配合样式。但常规的数字本地化、货币、百分比、紧凑计数和单位显示,用它比手写规则靠谱得多,也省掉了大量 locale 判断代码。 推荐查看天气:http://www.362tq.com/jiancaoping/ 推荐查看天气:http://www.362tq.com/jiancaoping/zuotian.html 推荐查看天气:http://www.362tq.com/jiancaoping/7tian.html 推荐查看天气:http://www.362tq.com/jiancaoping/10tian.html 推荐查看天气:http://www.362tq.com/jiancaoping/15tian.html 推荐查看天气:http://www.362tq.com/jiancaoping/40tian.html 推荐查看天气:http://www.362tq.com/wanbailin/ 推荐查看天气:http://www.362tq.com/wanbailin/zuotian.html 推荐查看天气:http://www.362tq.com/wanbailin/7tian.html 推荐查看天气:http://www.362tq.com/wanbailin/10tian.html 推荐查看天气:http://www.362tq.com/wanbailin/15tian.html 推荐查看天气:http://www.362tq.com/wanbailin/40tian.html 推荐查看天气:http://www.362tq.com/jinyuan/ 推荐查看天气:http://www.362tq.com/jinyuan/zuotian.html 推荐查看天气:http://www.362tq.com/jinyuan/7tian.html 推荐查看天气:http://www.362tq.com/jinyuan/10tian.html 推荐查看天气:http://www.362tq.com/jinyuan/15tian.html 推荐查看天气:http://www.362tq.com/jinyuan/40tian.html 推荐查看天气:http://www.362tq.com/qingxu/ 推荐查看天气:http://www.362tq.com/qingxu/zuotian.html 推荐查看天气:http://www.362tq.com/qingxu/7tian.html 推荐查看天气:http://www.362tq.com/qingxu/10tian.html 推荐查看天气:http://www.362tq.com/qingxu/15tian.html 推荐查看天气:http://www.362tq.com/qingxu/40tian.html 推荐查看天气:http://www.362tq.com/yangqu/ 推荐查看天气:http://www.362tq.com/yangqu/zuotian.html 推荐查看天气:http://www.362tq.com/yangqu/7tian.html 推荐查看天气:http://www.362tq.com/yangqu/10tian.html 推荐查看天气:http://www.362tq.com/yangqu/15tian.html 推荐查看天气:http://www.362tq.com/yangqu/40tian.html 推荐查看天气:http://www.362tq.com/loufan/ 推荐查看天气:http://www.362tq.com/loufan/zuotian.html 推荐查看天气:http://www.362tq.com/loufan/7tian.html 推荐查看天气:http://www.362tq.com/loufan/10tian.html 推荐查看天气:http://www.362tq.com/loufan/15tian.html 推荐查看天气:http://www.362tq.com/loufan/40tian.html 推荐查看天气:http://www.362tq.com/gujiao/ 推荐查看天气:http://www.362tq.com/gujiao/zuotian.html 推荐查看天气:http://www.362tq.com/gujiao/7tian.html 推荐查看天气:http://www.362tq.com/gujiao/10tian.html 推荐查看天气:http://www.362tq.com/gujiao/15tian.html 推荐查看天气:http://www.362tq.com/gujiao/40tian.html 推荐查看天气:http://www.362tq.com/datongshi/ 推荐查看天气:http://www.362tq.com/datongshi/zuotian.html 推荐查看天气:http://www.362tq.com/datongshi/7tian.html 推荐查看天气:http://www.362tq.com/datongshi/10tian.html 推荐查看天气:http://www.362tq.com/datongshi/15tian.html 推荐查看天气:http://www.362tq.com/datongshi/40tian.html 推荐查看天气:http://www.362tq.com/nanjiao/ 推荐查看天气:http://www.362tq.com/nanjiao/zuotian.html 推荐查看天气:http://www.362tq.com/nanjiao/7tian.html 推荐查看天气:http://www.362tq.com/nanjiao/10tian.html 推荐查看天气:http://www.362tq.com/nanjiao/15tian.html 推荐查看天气:http://www.362tq.com/nanjiao/40tian.html 推荐查看天气:http://www.362tq.com/xinrong/ 推荐查看天气:http://www.362tq.com/xinrong/zuotian.html 推荐查看天气:http://www.362tq.com/xinrong/7tian.html 推荐查看天气:http://www.362tq.com/xinrong/10tian.html 推荐查看天气:http://www.362tq.com/xinrong/15tian.html 推荐查看天气:http://www.362tq.com/xinrong/40tian.html 推荐查看天气:http://www.362tq.com/yanggao/ 推荐查看天气:http://www.362tq.com/yanggao/zuotian.html 推荐查看天气:http://www.362tq.com/yanggao/7tian.html 推荐查看天气:http://www.362tq.com/yanggao/10tian.html 推荐查看天气:http://www.362tq.com/yanggao/15tian.html 推荐查看天气:http://www.362tq.com/yanggao/40tian.html 推荐查看天气:http://www.362tq.com/tianzhen/ 推荐查看天气:http://www.362tq.com/tianzhen/zuotian.html 推荐查看天气:http://www.362tq.com/tianzhen/7tian.html 推荐查看天气:http://www.362tq.com/tianzhen/10tian.html 推荐查看天气:http://www.362tq.com/tianzhen/15tian.html 推荐查看天气:http://www.362tq.com/tianzhen/40tian.html 推荐查看天气:http://www.362tq.com/datongguangling/ 推荐查看天气:http://www.362tq.com/datongguangling/zuotian.html 推荐查看天气:http://www.362tq.com/datongguangling/7tian.html 推荐查看天气:http://www.362tq.com/datongguangling/10tian.html 推荐查看天气:http://www.362tq.com/datongguangling/15tian.html 推荐查看天气:http://www.362tq.com/datongguangling/40tian.html 推荐查看天气:http://www.362tq.com/lingqiu/ 推荐查看天气:http://www.362tq.com/lingqiu/zuotian.html 推荐查看天气:http://www.362tq.com/lingqiu/7tian.html 推荐查看天气:http://www.362tq.com/lingqiu/10tian.html 推荐查看天气:http://www.362tq.com/lingqiu/15tian.html 推荐查看天气:http://www.362tq.com/lingqiu/40tian.html 推荐查看天气:http://www.362tq.com/hunyuan/ 推荐查看天气:http://www.362tq.com/hunyuan/zuotian.html 推荐查看天气:http://www.362tq.com/hunyuan/7tian.html 推荐查看天气:http://www.362tq.com/hunyuan/10tian.html 推荐查看天气:http://www.362tq.com/hunyuan/15tian.html 推荐查看天气:http://www.362tq.com/hunyuan/40tian.html 推荐查看天气:http://www.362tq.com/zuoyun/ 推荐查看天气:http://www.362tq.com/zuoyun/zuotian.html 推荐查看天气:http://www.362tq.com/zuoyun/7tian.html 推荐查看天气:http://www.362tq.com/zuoyun/10tian.html 推荐查看天气:http://www.362tq.com/zuoyun/15tian.html 推荐查看天气:http://www.362tq.com/zuoyun/40tian.html 推荐查看天气:http://www.362tq.com/datongxian/ 推荐查看天气:http://www.362tq.com/datongxian/zuotian.html 推荐查看天气:http://www.362tq.com/datongxian/7tian.html 推荐查看天气:http://www.362tq.com/datongxian/10tian.html 推荐查看天气:http://www.362tq.com/datongxian/15tian.html 推荐查看天气:http://www.362tq.com/datongxian/40tian.html 推荐查看天气:http://www.362tq.com/yangquan/ 推荐查看天气:http://www.362tq.com/yangquan/zuotian.html 推荐查看天气:http://www.362tq.com/yangquan/7tian.html 推荐查看天气:http://www.362tq.com/yangquan/10tian.html 推荐查看天气:http://www.362tq.com/yangquan/15tian.html 推荐查看天气:http://www.362tq.com/yangquan/40tian.html 推荐查看天气:http://www.362tq.com/kuangqu/ 推荐查看天气:http://www.362tq.com/kuangqu/zuotian.html 推荐查看天气:http://www.362tq.com/kuangqu/7tian.html 推荐查看天气:http://www.362tq.com/kuangqu/10tian.html 推荐查看天气:http://www.362tq.com/kuangqu/15tian.html 推荐查看天气:http://www.362tq.com/kuangqu/40tian.html 推荐查看天气:http://www.362tq.com/pingding/ 推荐查看天气:http://www.362tq.com/pingding/zuotian.html 推荐查看天气:http://www.362tq.com/pingding/7tian.html 推荐查看天气:http://www.362tq.com/pingding/10tian.html 推荐查看天气:http://www.362tq.com/pingding/15tian.html 推荐查看天气:http://www.362tq.com/pingding/40tian.html 推荐查看天气:http://www.362tq.com/yuxian/ 推荐查看天气:http://www.362tq.com/yuxian/zuotian.html 推荐查看天气:http://www.362tq.com/yuxian/7tian.html 推荐查看天气:http://www.362tq.com/yuxian/10tian.html 推荐查看天气:http://www.362tq.com/yuxian/15tian.html 推荐查看天气:http://www.362tq.com/yuxian/40tian.html 推荐查看天气:http://www.362tq.com/changzhi/ 推荐查看天气:http://www.362tq.com/changzhi/zuotian.html 推荐查看天气:http://www.362tq.com/changzhi/7tian.html 推荐查看天气:http://www.362tq.com/changzhi/10tian.html 推荐查看天气:http://www.362tq.com/changzhi/15tian.html 推荐查看天气:http://www.362tq.com/changzhi/40tian.html 推荐查看天气:http://www.362tq.com/xiangyuan/ 推荐查看天气:http://www.362tq.com/xiangyuan/zuotian.html 推荐查看天气:http://www.362tq.com/xiangyuan/7tian.html 推荐查看天气:http://www.362tq.com/xiangyuan/10tian.html 推荐查看天气:http://www.362tq.com/xiangyuan/15tian.html 推荐查看天气:http://www.362tq.com/xiangyuan/40tian.html 推荐查看天气:http://www.362tq.com/tunliu/ 推荐查看天气:http://www.362tq.com/tunliu/zuotian.html 推荐查看天气:http://www.362tq.com/tunliu/7tian.html 推荐查看天气:http://www.362tq.com/tunliu/10tian.html 推荐查看天气:http://www.362tq.com/tunliu/15tian.html 推荐查看天气:http://www.362tq.com/tunliu/40tian.html 推荐查看天气:http://www.362tq.com/pingshun/ 推荐查看天气:http://www.362tq.com/pingshun/zuotian.html 推荐查看天气:http://www.362tq.com/pingshun/7tian.html 推荐查看天气:http://www.362tq.com/pingshun/10tian.html 推荐查看天气:http://www.362tq.com/pingshun/15tian.html 推荐查看天气:http://www.362tq.com/pingshun/40tian.html 推荐查看天气:http://www.362tq.com/changzhilicheng/ 推荐查看天气:http://www.362tq.com/changzhilicheng/zuotian.html 推荐查看天气:http://www.362tq.com/changzhilicheng/7tian.html 推荐查看天气:http://www.362tq.com/changzhilicheng/10tian.html 推荐查看天气:http://www.362tq.com/changzhilicheng/15tian.html 推荐查看天气:http://www.362tq.com/changzhilicheng/40tian.html 推荐查看天气:http://www.362tq.com/huguan/ 推荐查看天气:http://www.362tq.com/huguan/zuotian.html 推荐查看天气:http://www.362tq.com/huguan/7tian.html 推荐查看天气:http://www.362tq.com/huguan/10tian.html 推荐查看天气:http://www.362tq.com/huguan/15tian.html 推荐查看天气:http://www.362tq.com/huguan/40tian.html 推荐查看天气:http://www.362tq.com/changzi/ 推荐查看天气:http://www.362tq.com/changzi/zuotian.html 推荐查看天气:http://www.362tq.com/changzi/7tian.html 推荐查看天气:http://www.362tq.com/changzi/10tian.html 推荐查看天气:http://www.362tq.com/changzi/15tian.html 推荐查看天气:http://www.362tq.com/changzi/40tian.html 推荐查看天气:http://www.362tq.com/wuxiang/ 推荐查看天气:http://www.362tq.com/wuxiang/zuotian.html 推荐查看天气:http://www.362tq.com/wuxiang/7tian.html 推荐查看天气:http://www.362tq.com/wuxiang/10tian.html 推荐查看天气:http://www.362tq.com/wuxiang/15tian.html 推荐查看天气:http://www.362tq.com/wuxiang/40tian.html 推荐查看天气:http://www.362tq.com/qinxian/ 推荐查看天气:http://www.362tq.com/qinxian/zuotian.html 推荐查看天气:http://www.362tq.com/qinxian/7tian.html 推荐查看天气:http://www.362tq.com/qinxian/10tian.html 推荐查看天气:http://www.362tq.com/qinxian/15tian.html 推荐查看天气:http://www.362tq.com/qinxian/40tian.html 推荐查看天气:http://www.362tq.com/qinyuan/ 推荐查看天气:http://www.362tq.com/qinyuan/zuotian.html 推荐查看天气:http://www.362tq.com/qinyuan/7tian.html 推荐查看天气:http://www.362tq.com/qinyuan/10tian.html 推荐查看天气:http://www.362tq.com/qinyuan/15tian.html 推荐查看天气:http://www.362tq.com/qinyuan/40tian.html 推荐查看天气:http://www.362tq.com/shuozhou/ 推荐查看天气:http://www.362tq.com/shuozhou/zuotian.html 推荐查看天气:http://www.362tq.com/shuozhou/7tian.html 推荐查看天气:http://www.362tq.com/shuozhou/10tian.html 推荐查看天气:http://www.362tq.com/shuozhou/15tian.html 推荐查看天气:http://www.362tq.com/shuozhou/40tian.html 推荐查看天气:http://www.362tq.com/shuocheng/ 推荐查看天气:http://www.362tq.com/shuocheng/zuotian.html 推荐查看天气:http://www.362tq.com/shuocheng/7tian.html 推荐查看天气:http://www.362tq.com/shuocheng/10tian.html 推荐查看天气:http://www.362tq.com/shuocheng/15tian.html 推荐查看天气:http://www.362tq.com/shuocheng/40tian.html 推荐查看天气:http://www.362tq.com/shuozhoupinglu/ 推荐查看天气:http://www.362tq.com/shuozhoupinglu/zuotian.html