全面讲解在JavaScript中格式化数字与日期的常用方法,涵盖原生Intl国际化API、内置方法、自定义模板函数及实际开发中的避坑指南。
JavaScript中格式化数字与日期的常用方法
时间:2026-10-30
浏览:649
文章目录
在前端与 Node.js 业务开发中,将原始的数字(金额、百分比、千分位数值)和日期(时间戳、Date 对象)转换为用户友好的排版格式是高频需求。现代 JavaScript 提供了功能强大的国际化标准 API(Intl.NumberFormat 与 Intl.DateTimeFormat),它们属于原生内置支持,具备极佳的运行性能与跨语言环境能力;同时,结合适度的原生原型方法与轻量模板函数,即可覆盖从高精度财务报表到日常界面展示的绝大多数格式化场景。
一、JavaScript 中格式化数字的核心方法
处理数字展示时,常见需求包括:保留固定小数位、添加千分位分隔符、格式化为法币符号、转换为百分比或缩写大数值。实现方式主要分为原生 Intl.NumberFormat、数值原型方法与自定义正则处理。
1. 使用 Intl.NumberFormat(现代标准方案)
Intl.NumberFormat 是 ECMAScript 国际化 API 规范的一部分。它支持根据指定区域(Locale)自动应用排版规则,例如中文千分位用逗号、德语使用点号等,且原生支持货币与百分比格式化。
// 基础千分位格式化
const num = 1234567.89;
const standardFormatter = new Intl.NumberFormat('zh-CN');
console.log(standardFormatter.format(num));
// 货币格式化:人民币与美元
const cnyFormatter = new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY',
minimumFractionDigits: 2
});
console.log(cnyFormatter.format(num));
const usdFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
console.log(usdFormatter.format(num));
// 百分比格式化
const ratio = 0.2856;
const percentFormatter = new Intl.NumberFormat('zh-CN', {
style: 'percent',
minimumFractionDigits: 1,
maximumFractionDigits: 2
});
console.log(percentFormatter.format(ratio));
// 大数值紧凑缩写(如:1.2万 / 1.2M)
const compactFormatter = new Intl.NumberFormat('zh-CN', {
notation: 'compact'
});
console.log(compactFormatter.format(12500000));
1,234,567.89
¥1,234,567.89
$1,234,567.89
28.56%
1250万
2. 使用 toFixed 与 toLocaleString 原生方法
Number.prototype.toFixed() 常用于快速截断并保留指定小数位数,返回字符串。但需注意它遵循的是“舍入到最近的偶数”(银行家舍入法)以及浮点数存储偏差,在严格四舍五入要求下需要辅助逻辑。
const price = 45.678;
// 保留两位小数
console.log(price.toFixed(2));
// 直接调用 Number.prototype.toLocaleString()
const balance = 9876543.21;
console.log(balance.toLocaleString('zh-CN', { minimumFractionDigits: 2 }));
45.68
9,876,543.21
3. 正则表达式实现轻量千分位
在不引入外部库且仅需要简单千分位分割的轻量场景下,可以使用前瞻断言正则表达式完成转换:
function formatThousands(num) {
if (num === null || num === undefined || isNaN(num)) return '0';
const parts = num.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
}
console.log(formatThousands(88481234.56));
二、数字格式化规范流程与执行步骤
在企业级业务系统(如后台对账、订单报表)中,直接调用未封装的方法容易遇到 null 报错、NaN 脏数据或频繁实例化导致的性能抖动。规范的操作步骤应当建立完备的校验与实例复用机制。
可复用的生产级数字格式化封装函数
// 实例缓存池,避免高频调用时的性能损耗
const numberFormatterPool = new Map();
function formatCurrency(amount, currency = 'CNY', decimals = 2) {
if (amount === null || amount === undefined || isNaN(Number(amount))) {
return '--';
}
const cacheKey = `${currency}_${decimals}`;
if (!numberFormatterPool.has(cacheKey)) {
numberFormatterPool.set(
cacheKey,
new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: currency,
minimumFractionDigits: decimals,
maximumFractionDigits: decimals
})
);
}
return numberFormatterPool.get(cacheKey).format(Number(amount));
}
console.log(formatCurrency(899.5));
console.log(formatCurrency(null));
¥899.50
--
三、JavaScript 中格式化日期的常用方法
日期时间格式化的核心是把时间戳(毫秒/秒)或 Date 对象转成符合具体语境的文本(如 2026-10-24 12:00:00 或 2026年10月24日 星期六)。
1. 使用 Intl.DateTimeFormat(推荐原生标准)
与数字格式化类似,Intl.DateTimeFormat 原生支持设置年份、月份、日期、星期、12/24小时制以及时区参数(timeZone)。
const now = new Date('2026-10-24T12:08:29Z');
// 常见中文日期长格式
const dtfCn = new Intl.DateTimeFormat('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
console.log(dtfCn.format(now));
// 跨时区展示:指定转换为纽约时间 (America/New_York)
const dtfNy = new Intl.DateTimeFormat('en-US', {
timeZone: 'America/New_York',
dateStyle: 'medium',
timeStyle: 'short'
});
console.log(dtfNy.format(now));
2026年10月24日星期六 20:08:29(依本地时区转换结果)
Oct 24, 2026, 8:08 AM
2. 使用 Date 原生简便方法
对于无需复杂配置的小型项目,原生 Date 对象的自带方法非常轻便:
date.toISOString():返回 ISO-8601 标准零时区格式(如2026-10-24T12:08:29.000Z),适合接口持久化。date.toLocaleDateString():输出符合系统语言的纯日期部分。date.toLocaleTimeString():输出符合系统语言的纯时间部分。
3. 轻量级通用模板替换函数(无依赖)
许多中文业务场景严格要求输出 YYYY-MM-DD HH:mm:ss 形式。通过简单的正则字典替换,无需引入大型外部日期库即可实现:
function formatDate(input, format = 'YYYY-MM-DD HH:mm:ss') {
const d = input instanceof Date ? input : new Date(input);
if (isNaN(d.getTime())) return '';
const pad = (n) => String(n).padStart(2, '0');
const map = {
YYYY: d.getFullYear(),
MM: pad(d.getMonth() + 1),
DD: pad(d.getDate()),
HH: pad(d.getHours()),
mm: pad(d.getMinutes()),
ss: pad(d.getSeconds())
};
return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (matched) => map[matched]);
}
const testDate = new Date(1761278909000);
console.log(formatDate(testDate, 'YYYY-MM-DD HH:mm:ss'));
console.log(formatDate(testDate, 'YYYY/MM/DD'));
2025-10-24 12:08:29
2025/10/24
四、方案对比与选型决策指南
面对不同的业务体量和场景特征,开发者应当根据项目依赖预算、性能要求以及本地化需求选择合适的技术路径:
| 技术方案 | 适用场景 | 主要优势 | 局限与注意事项 |
|---|---|---|---|
| Intl.NumberFormat | 国际化货币、百分比、大数缩写、标准化千分位 | 现代浏览器原生标准、无需引入三方库、多语言支持完备 | 旧版本 IE 不支持;在循环中频繁 new 会产生性能开销(应复用实例) |
| Intl.DateTimeFormat | 跨时区时间转换、本地化星期/月份排版、相对时间 | 原生时区数据库换算、支持长/短/完整日期风格 | 对非常规自定义格式(如仅替换指定占位符)配置稍显繁琐 |
| toFixed / 正则千分位 | 单一数字截断、国内后台简单表格排版 | 轻便快速、代码极短、执行无额外抽象层 | 存在浮点数舍入偏差;不支持语言环境自适应 |
| 手写 formatDate 模板函数 | 固定的 YYYY-MM-DD HH:mm:ss 业务展示 |
零打包体积、行为稳定透明、可控性极高 | 不具备时区转换能力,依赖当前运行宿主本地时间 |
| 三方轻量库 (Day.js 等) | 涉及复杂时间加减、比较、区间计算与复杂相对时间 | API 链式调用友好、生态插件丰富(约 2KB) | 增加项目外部依赖;若仅展示日期则可能造成性能冗余 |
五、常见陷阱与工程最佳实践
JavaScript 使用 IEEE 754 双精度浮点数存储,因此 0.1 + 0.2 !== 0.3,而 1.005.toFixed(2) 会意外输出 "1.00" 而不是 "1.01"。在金融计费等高精度场景中,金额应在后端统一以最小货币单位(如“分”)存储为整数,或前端使用定点运算辅助库,再进行最终展示层格式化。
为了保障生产代码的稳健性,建议在实际项目中遵守以下三项工程规范:
- 防御性空值处理:在格式化函数入口处统一判断
null、undefined、空字符串与NaN,并约定统一的占位符号(如"--"或"0.00"),防止页面崩溃。 - 时区显式声明:在多地区协作或国际化项目中,接口传输的时间统一采用 UTC 时间戳或携带时区偏移的 ISO 字符串(如
2026-10-24T04:08:29Z),客户端渲染时若需固定为北京时间,必须显式传入timeZone: 'Asia/Shanghai',切勿依赖用户本机的操作系统时区设置。 - 重用 Intl 实例:构造
Intl.NumberFormat或Intl.DateTimeFormat的耗时明显高于普通函数调用。在长表格、大数据看板渲染时,必须通过缓存池单例复用实例,可大幅减少垃圾回收与构造开销。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。