前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Intl.NumberFormat currency 货币格式化
JavaScript数据处理

显示金额时,为什么不要写 '$' + amount,而要用 Intl.NumberFormat?

手动拼 '$' + amount 会漏掉千分位、小数位和符号位置,还分不清美元和加元。new Intl.NumberFormat(locale, { style: 'currency', currency: 'USD' }) 按语言和币种一起处理:美国是 $1,234.50,德国是 1.234,50 €,日元默认不带小数。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数据处理
先看核心答案读代码示例
理解线索

金额数值、币种、显示习惯是三件事

  1. 金额业务层存的数值,最好用「分」这样的整数,不带任何符号
  2. currencyUSD、CNY、JPY 这样的 ISO 4217 代码,决定符号和默认小数位
  3. locale决定千分位用逗号还是点、符号放前面还是后面

格式化后的字符串里可能有不换行空格(U+00A0),比如德语的 1.234,50 €。拿它和手写的普通空格字符串做 === 比较,或者在测试里写死断言,很容易莫名失败。

核心回答

先记住这个答案

货币格式不只是在数字前面加个符号。千分位用逗号还是点、小数保留几位、符号放前面还是后面、负数怎么写,每个国家、每种货币都有自己的习惯。Intl.NumberFormat 的 style: 'currency' 模式会根据 locale 和 currency 两个参数一起处理这些细节。currency 必须传 ISO 货币码,比如 USD、CNY 或 JPY,它不仅决定符号,还决定默认的小数位数,日元默认就是 0 位。手动 '$' + amount 既处理不了这些,也区分不了美元和加元这种都用 $ 的货币。

  • 同时传 locale、style 和 ISO 货币码
  • 小数位跟着币种走,日元默认 0 位
  • 同一个 $ 可能是美元也可能是加元,靠 currency 区分
  • 格式化只管显示,不解决 0.1 + 0.2 的精度问题

同一个数字,不同币种和地区

一个跨境电商页面,同样的价格数字要按用户的地区和结算币种显示。

显式传入地区和货币码JavaScript
const amount = 1234.5
const money = (locale, currency, extra = {}) =>
  new Intl.NumberFormat(locale, { style: 'currency', currency, ...extra }).format(amount)

console.log(money('en-US', 'USD')) // 美元,补齐两位小数
console.log(money('zh-CN', 'CNY')) // 人民币
console.log(money('ja-JP', 'JPY')) // 日元没有小数,四舍五入
console.log(money('en-US', 'CAD')) // 加元,自动加上 CA 前缀区分
console.log(money('en-US', 'CAD', { currencyDisplay: 'narrowSymbol' }))
查看输出与解释
$1,234.50
¥1,234.50
¥1,235
CA$1,234.50
$1,234.50

日元那行值得注意:1234.5 被四舍五入成了 1235,因为日元的最小单位就是 1 元,格式化器默认按 0 位小数显示。如果你手写 toFixed(2),日本用户会看到奇怪的 1234.50。 加元那行,美国用户看到的是 CA$,因为在美国语境里单写 $ 就是美元。currencyDisplay: 'narrowSymbol' 强制只显示 $,适合空间紧凑、币种已经在别处写明的界面。另外两个取值里,code 显示成 CAD 1,234.50,而 name 显示成 1,234.50 Canadian dollars。

符号位置和分隔符也会变
换成德国用户看欧元,new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }) 输出的是 1.234,50 €。千分位变成了点,小数点变成了逗号,符号跑到了后面,中间还是一个不换行空格。这些规则如果自己写,每加一个市场就要改一次代码。

格式化只管显示,不管计算

Intl.NumberFormat 输出的是给人看的字符串。它解决不了浮点数计算误差,也不该拿去做后续计算。

精度问题要在格式化之前解决JavaScript
const fmt = new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' })

console.log(0.1 + 0.2) // 浮点误差还在
console.log(fmt.format(0.1 + 0.2)) // 显示时被舍入掩盖了

// 推荐:金额用「分」存整数,显示前再除以 100
const priceInCents = 1999 + 2999
console.log(fmt.format(priceInCents / 100))
查看输出与解释
0.30000000000000004
¥0.30
¥49.98

第二行看起来没问题,是因为格式化器舍入到了两位小数,误差被藏起来了。但如果你拿格式化前的值继续算,累加几百次、再和后端对账,就可能差出一分钱。账务计算要么用整数的分,要么用 decimal.js 这类十进制库,格式化只在最后一步显示时做。 同样的道理,格式化后的字符串不要拿去排序、提交或者反向解析成数字。数据层始终保留原始数值和币种,视图层最后才格式化。

回答前,多想一步

容易答错的地方

以为 locale 能决定币种
zh-CN 不代表人民币。style: 'currency' 时 currency 是必填的,不传直接抛 TypeError。一个中国用户看美元订单,就是 locale 为 zh-CN、currency 为 USD,两者是独立的。
用 toFixed(2) 统一处理小数
不是所有货币都有两位小数。日元、韩元是 0 位,科威特第纳尔是 3 位。让格式化器按币种的默认规则走;产品确实要求固定位数时,再显式设置 minimumFractionDigits 和 maximumFractionDigits。
试着用自己的话回答

面试官还会怎么问?

财务报表里负数要显示成括号,怎么做?

加 currencySign: 'accounting'。在 en-US 下,-5 美元会显示成 ($5.00),而不是默认的 -$5.00。是否支持括号写法取决于语言,有的语言会继续用负号。

怎么把货币符号单独加样式,比如写小一号?

用 formatToParts()。它返回 currency、integer、group、decimal、fraction 这些片段,给 type 为 currency 的那段套上样式,其余按原顺序输出。不要自己拆字符串,因为符号可能在前也可能在后。

列表里几百个价格,性能怎么优化?

把 formatter 实例建一次,重复用它的 format()。每次 new 都要解析语言数据和货币数据,放在渲染循环里开销很大。可以按 locale 加 currency 做一个简单的缓存 Map。

从一道题,走向一组知识

把知识连起来

数据处理

很大或很小的数字,怎么用 Intl.NumberFormat 显示成科学计数法?

同一个 Intl.NumberFormat,其中 style 管货币、百分比、单位,而 notation 管科学计数法和紧凑写法,两题合起来就是它的全部常用选项。

数据处理

做多语言时,「1 file / 2 files」这种单复数怎么写才对?

「共 3 件商品,合计 ¥99」这种文案,数字部分用 Intl.NumberFormat,量词的单复数用 Intl.PluralRules。

参考资料

  • JavaScript:数据处理参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 同一个数字,不同币种和地区
  3. 格式化只管显示,不管计算
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑