JS 大数值处理和金额格式化处理方案
点赞 + 关注 + 收藏 = 学会了 在做前端开发或者使用 n8n、dify 等工具时可能会跟数字打交道,可能会遇到下面这些需求: 很多刚接触 JavaScript 的开发者会直接使用 举个例子: 如果后端传给你的 JSON 里的长 ID 没加引号,前端在 解决方案: 在实际应用中,可以通过一些方法来胖段当前数值是否安全。 JS 提供的方法: 在 JavaScript 里,普通数字类型是 超过这个范围就会出现 精度丢失问题,例如: 如果你要处理 超过 Number 最大安全值的整数,有几种常见方案👇 现代 JavaScript 提供了一种新的类型: 它可以表示任意大的整数。 用 它还有一种简写方法,在赋值的时候不需要加引号括者数字,而是在数字后面加个 需要注意的是,BigInt 不能和 Number 混合运算!!! 必须统一类型: 一个经典问题: 原因是浮点数精度问题。 金融系统一般有两种解决方案。 例如: 前端展示时再除以 100。 这种方式是比较老派的方法。 **MikeMcl 写了几个很出名的处理数字的JS库,比如: 我用 bignumber.js 演示一下。 安装 bignumber.js 在前端项目里引入: 此时直接计算小数位的数值 处理数值比较大的数据也没问题 在金融行业,金额的展示不仅关乎美观,更关乎准确性和合规性。针对你提出的千分位转换、中文大写转换以及大数处理 JavaScript 原生支持国际化格式化。 金融项目比较推荐使用这个方案。 如果想在金额前面加一个“钱”的符号,比如人民币就加个 如果要使用美元符 如果需要支持小数就这么写: 但金融系统一般不推荐这种方式,因为这种方式不支持国际化,不支持货币格式,容易出 bug。 在中文的金融系统中,经常需要展示: 这个规则有点复杂,一般不建议自己实现。 我推荐使用开源库 nzh(https://github.com/cnwhy/nzh)。 安装: 使用: 最后总结一下。 在 JavaScript 中处理金额和大数时,核心要记住三点: 1️⃣ 不要直接用 Number 做金融计算 只要遵循这三条原则,就可以避免绝大多数金额相关的 bug。 以上就是本文的全部内容了,还有疑问的话可以在评论区交流。 点赞 + 关注 + 收藏 = 学会了1234567.89 → 1,234,567.890.1 + 0.29007199254740993123456.78 → 壹拾贰万叁仟肆佰伍拾陆元柒角捌分Number 类型处理这些问题,但实际上这里面隐藏了不少 坑。JSON.parse 的一瞬间就已经把精度丢了。const rawJson = '{"id": 9007199254740995}';
const parsed = JSON.parse(rawJson);
console.log(parsed.id.toString()); // "9007199254740996" 精度丢失了!!!json-bigint 库来解析原始的 JSON 字符串。数值是否安全?
Number.isSafeInteger(9007199254740991) // true
Number.isSafeInteger(9007199254740992) // false处理大数值的几种方案
Number(64位双精度浮点),它有一个安全整数范围:Number.MAX_SAFE_INTEGER = 9007199254740991Number.MIN_SAFE_INTEGER = -9007199254740991console.log(9007199254740991 + 1) // 9007199254740992
console.log(9007199254740991 + 2) // 9007199254740992 ❌ 精度丢失方案1:BigInt
BigInt。const num = BigInt("9007199254740993")
console.log(num + 1n)
// 9007199254740994nBigInt 的话,数字后面会跟着一个字母 n,看到它就能区分这个值和普通的 Number 类型不一样,这个需求可能会涉及很大的数值。n。const num = 9007199254740993n1n + 1
// ❌ 报错1n + BigInt(1)金融计算为什么不能直接用 Number
0.1 + 0.2
# 结果是 0.30000000000000004方案一:金额用“分”存储
123.45 元
存储为:12345 分const amount = 12345 / 100
console.log(amount)
// 123.45方案二:使用大数库
npm install bignumber.jsimport BigNumber from 'bignumber.js';const a = new BigNumber(0.1)
const b = new BigNumber(0.2)
a.plus(b).toString()
// 0.3
// 格式化,保留2位小数
a.plus(b).toFormat(2)
// 0.30// 1. 创建大数(建议始终传入字符串)
const x = new BigNumber('9007199254740995.123456789');
const y = new BigNumber('100');
// 2. 加减乘除
const res = x.plus(y); // 加
const res2 = x.minus(y); // 减
const res3 = x.times(y); // 乘
const res4 = x.div(y); // 除
console.log(res.toString()); // "9007199254741095.123456789" (精度完全保留)格式化数值
千分位格式化
方案1:
toLocaleString()const amount = 123456789.56
amount.toLocaleString()
// 123,456,789.56方案2:
Intl.NumberFormatconst formatter = new Intl.NumberFormat('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})
console.log(formatter.format(1234567.8))
// 1,234,567.80¥,可以这么写:const formatter = new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY'
})
console.log(formatter.format(123456))
// ¥123,456.00$ 就这么写:const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
})
console.log(formatter.format(123456))
// $123,456.00方案3:正则实现千分位(不推荐)
function formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}
console.log(formatNumber(123456789))
// 123,456,789function formatMoney(num) {
return num.toString().replace(/\d+/, function(n) {
return n.replace(/(\d)(?=(\d{3})+$)/g, '$1,')
})
}数字转大写中文
123456.78
↓
壹拾贰万叁仟肆佰伍拾陆元柒角捌分npm install nzhimport nzh from "nzh"
nzh.cn.encodeS(123456)
// 十二万三千四百五十六
nzh.cn.encodeB(123456.78)
// 壹拾贰万叁仟肆佰伍拾陆点柒捌
nzh.cn.toMoney(123456.78)
// 人民币壹拾贰万叁仟肆佰伍拾陆元柒角捌分
2️⃣ 金额存储最好使用整数(分)
3️⃣ 展示时再进行格式化