big.js
上手教程(最全最详细)big.js
是一个轻量级的 JavaScript 库,用于处理 高精度浮点数运算。它解决了 JavaScript 原生浮点数精度丢失的问题,适用于金融计算、科学计算等对精度要求极高的场景。
JS 浮点数问题示例:
0.1 + 0.2; // 0.30000000000000004 ❌ 精度错误
使用 big.js
后:
new Big(0.1).plus(0.2).toString(); // '0.3' ✅ 精确结果
BigNumber.js
big.js
,成为 GitHub 上最受欢迎的高精度数字库之一npm install big.js
// 引入
const Big = require('big.js');
<script src="https://cdn.jsdelivr.net/npm/[email protected]/big.min.js">script>
const result = new Big(123.456);
new Big(n: number | string | Big): Big
参数类型 | 示例 | 说明 |
---|---|---|
数字 | new Big(123.45) |
推荐使用字符串避免精度丢失 |
字符串 | new Big('123.45') |
最推荐方式,确保精确解析 |
Big 对象 | new Big(new Big(123)) |
克隆 |
⚠️ 不建议传入复杂表达式或函数,应先转换为字符串或数字。
方法名 | 功能 | 示例 |
---|---|---|
.plus(n) |
加法 | new Big(0.1).plus(0.2) |
.minus(n) |
减法 | new Big(1.2).minus(0.7) |
.times(n) |
乘法 | new Big(1.2).times(3) |
.div(n[, dp]) |
除法(可指定小数位) | new Big(1).div(3, 2) |
.mod(n) |
取模 | new Big(10).mod(3) |
.pow(exp) |
幂运算 | new Big(2).pow(10) |
.round(dp, rm) |
四舍五入 | new Big(3.14159).round(2) |
.cmp(n) |
比较 | new Big(5).cmp(3) |
.eq(n) |
是否相等 | new Big(5).eq(5) |
.lt(n) / .lte(n) |
小于 / 小于等于 | new Big(2).lt(3) |
.gt(n) / .gte(n) |
大于 / 大于等于 | new Big(5).gt(3) |
.toNumber() |
转换为原生 Number | new Big(123).toNumber() |
.toString() |
输出字符串 | new Big(123.456).toString() |
.toFixed(dp) |
格式化固定小数位 | new Big(3.14159).toFixed(2) |
你可以通过 Big.DP
和 Big.RM
设置默认行为:
Big.DP = 20; // 默认保留 20 位小数
Big.RM = 1; // 舍入模式(0:四舍五入, 1:向下取整, 2:向上取整, 3:去尾法)
const amount1 = new Big('19.99');
const amount2 = new Big('5.49');
const total = amount1.plus(amount2); // '25.48'
console.log(total.toFixed(2)); // '25.48'
// 导入Big.js库
import Big from 'big.js';
// 定义美元金额
const usd = new Big('100');
// 定义汇率(1美元兑换7.25人民币)
const rate = new Big('7.25'); // USD to CNY
// 计算等值人民币金额
const cny = usd.times(rate); // 结果将是'725.00'
// 输出结果,保留两位小数
console.log(cny.toFixed(2)); // 输出: '725.00'
const price = new Big('29.99');
const quantity = 3;
const totalPrice = price.times(quantity); // '89.97'
console.log(totalPrice.toString());
const balance = new Big('1000000.00');
const withdrawal = new Big('999999.99');
if (withdrawal.lte(balance)) {
console.log('可以提现');
} else {
console.log('余额不足');
}
// 导入Big.js库
import Big from 'big.js';
// 定义基数
const base = new Big('2');
// 定义指数
const exponent = 64;
// 计算幂运算结果
const result = base.pow(exponent); // 结果将是18446744073709551616
// 输出结果
console.log(result.toString()); // 输出: '18446744073709551616'
// 导入Big.js库
import Big from 'big.js';
// 定义要转账的金额
const transferAmount = new Big('0.000000123456');
// 定义最小转账金额限制
const minTransfer = new Big('0.0000001');
// 检查转账金额是否满足最低要求
if (transferAmount.gte(minTransfer)) {
console.log('交易有效');
} else {
console.log('交易金额过低');
}
// 导入Big.js库
import Big from 'big.js';
// 定义数字数组
const values = ['12.34', '45.67', '89.01'];
// 使用reduce方法计算数组中所有数字的总和
// 初始值为new Big(0),然后对每个元素使用plus方法进行累加
const sum = values.reduce((acc, val) => acc.plus(val), new Big(0));
// 计算平均值
const avg = sum.div(values.length);
// 输出结果
console.log(`总和:${sum}`); // 输出: '147.02'
console.log(`平均值:${avg}`); // 输出: '49.00666666666666666666'
风险 | 描述 |
---|---|
❌ 不要混用 Big 与原生 Number 运算 | 如 new Big(1) + 1 会出错 |
❌ 不要将对象或函数传入构造函数 | 必须是数字或字符串 |
❌ 不要频繁创建 Big 实例 | 在循环或高频调用中注意性能优化 |
❌ 不要忘记 .toString() 或 .toFixed() 输出 |
否则返回的是 Big 对象引用 |
实践 | 说明 |
---|---|
✅ 总是使用字符串初始化 | 避免浮点精度问题 |
✅ 使用 .toFixed(n) 控制输出格式 |
特别是在 UI 显示时 |
✅ 使用 .eq() , .lt() , .gt() 替代 === , < , > |
避免类型强制转换错误 |
✅ 使用 Big.DP 设置默认精度 |
统一项目中的计算规则 |
✅ 使用 .round(dp, rm) 控制舍入 |
提高财务一致性 |
✅ 封装成工具类 | 提高复用性和可维护性 |
// 导入Big.js库,用于高精度数学运算
import Big from 'big.js';
/**
* 执行基本数学运算的函数
* @param op 运算类型:'add'(加法), 'sub'(减法), 'mul'(乘法), 'div'(除法)
* @param a 第一个操作数(字符串形式)
* @param b 第二个操作数(字符串形式)
* @returns 运算结果,保留两位小数的字符串
*/
function calc(op: 'add' | 'sub' | 'mul' | 'div', a: string, b: string): string {
// 将字符串参数转换为Big.js对象,以便进行高精度计算
const x = new Big(a);
const y = new Big(b);
// 根据操作符执行相应的数学运算
switch (op) {
case 'add':
// 执行加法运算,并将结果格式化为保留两位小数的字符串
return x.plus(y).toFixed(2);
case 'sub':
// 执行减法运算,并将结果格式化为保留两位小数的字符串
return x.minus(y).toFixed(2);
case 'mul':
// 执行乘法运算,并将结果格式化为保留两位小数的字符串
return x.times(y).toFixed(2);
case 'div':
// 执行除法运算,并将结果格式化为保留两位小数的字符串
return x.div(y).toFixed(2);
}
}
// 测试函数
console.log(calc('add', '10.01', '20.02')); // 输出: '30.03'
在 Vue 中,可在 methods或 utils.js
中封装:
// utils.js
import Big from 'big.js';
export function formatMoney(value: string | number): string {
return new Big(value).toFixed(2);
}
<template>
<div>总价:{{ formatMoney(total) }}</div>
</template>
<script>
import { formatMoney } from '@/utils';
export default {
data() {
return {
total: '123.456'
};
},
methods: {
formatMoney
}
};
</script>
错误 | 原因 | 解决方案 |
---|---|---|
NaN 错误 |
传入非法字符 | 使用前验证输入 |
Invalid Big value |
构造参数无效 | 确保是字符串或数字 |
Uncaught TypeError: Cannot convert instance of Big to primitive |
直接使用 + 运算符 |
改用 .plus() 方法 |
Exponential notation not supported |
输入含 e 科学计数法 | 先转为标准数字格式 |
big.js 要点 | 内容 |
---|---|
✅ 主要用途 | 高精度浮点数运算 |
✅ 优势 | 轻量、安全、跨平台 |
✅ 推荐使用场景 | 金融、支付、区块链、科学计算 |
✅ 注意事项 | 不要混用原生数字,控制精度 |
✅ 替代方案 | decimal.js(更强大但更大) |
big.js
面试题精选(10大高频面试题)JavaScript 使用 IEEE 754 浮点数标准,导致某些小数运算存在精度丢失问题。例如:
0.1 + 0.2; // 0.30000000000000004 ❌
big.js
提供了高精度的十进制运算能力,避免此类误差,适用于金融、支付等对精度要求极高的场景。
使用 big.js
示例:
new Big(0.1).plus(0.2).toString(); // '0.3' ✅
可以通过以下方式创建:
new Big(123); // 数字
new Big('123.45'); // 推荐:字符串(避免精度丢失)
new Big(new Big(123)); // Big 实例克隆
推荐方式是字符串初始化,因为直接传入浮点数可能会因 JS 原生解析而引入误差。
方法 | 功能 | 示例 |
---|---|---|
.plus(n) |
加法 | new Big(0.1).plus(0.2) |
.minus(n) |
减法 | new Big(1.2).minus(0.7) |
.times(n) |
乘法 | new Big(1.2).times(3) |
.div(n[, dp]) |
除法(可指定小数位) | new Big(1).div(3, 2) |
示例:
const result = new Big('10').div('3', 2); // '3.33'
<
或 >
?不能直接使用 <
或 >
,应使用如下方法:
a.eq(b); // 是否相等
a.lt(b); // a < b
a.gt(b); // a > b
a.lte(b); // a <= b
a.gte(b); // a >= b
正确写法:
const a = new Big('5');
const b = new Big('3');
console.log(a.gt(b)); // true
可以使用 .toFixed(dp)
和 .round(dp, rm)
控制格式化输出和舍入方式。
const num = new Big('3.14159');
num.toFixed(2); // '3.14'
num.round(3); // '3.142'
// 设置全局默认行为
Big.DP = 20; // 默认保留 20 位小数
Big.RM = 1; // 舍入模式(0:四舍五入, 1:向下取整, 2:向上取整, 3:去尾法)
Big.RM
支持以下舍入模式(共 4 种):
模式值 | 含义 |
---|---|
0 |
四舍五入(默认) |
1 |
向下取整(截断) |
2 |
向上取整 |
3 |
去尾法(不常用) |
示例:
Big.RM = 1;
new Big('3.999').round(0); // '3'
特性 | big.js |
decimal.js |
---|---|---|
体积 | 更小(压缩后 < 5KB) | 较大 |
功能 | 精简实用 | 更强大(支持指数、三角函数等) |
性能 | 更快 | 略慢 |
使用难度 | 简单易用 | 配置更复杂 |
适用场景 | 金融计算、基础数学 | 科学计算、复杂业务逻辑 |
选择建议:
big.js
decimal.js
是的,big.js
可以用于任何前端框架中,推荐封装成工具类或自定义 Hook / Filter。
Vue 封装示例:
// utils/bigUtils.ts
import Big from 'big.js';
export function formatMoney(value: string | number): string {
return new Big(value).toFixed(2);
}
<template>
<div>价格:{{ formatMoney(price) }}</div>
</template>
<script>
import { formatMoney } from '@/utils/bigUtils';
export default {
data() {
return {
price: '19.99'
};
},
methods: {
formatMoney
}
};
</script>
虽然 big.js
性能较好,但在高频循环或大数据处理中仍需注意:
示例优化:
let total = new Big(0);
for (let i = 0; i < items.length; i++) {
total = total.plus(items[i].price);
}
big.js
构造函数若传入非法参数会抛出异常,因此必须进行输入校验:
function safeParse(input) {
try {
return new Big(input);
} catch (e) {
console.error('无效数值:', input);
return new Big(0);
}
}
safeParse('abc'); // 输出 0,并提示错误
推荐做法:
题号 | 主题 |
---|---|
1 | JS 浮点数精度问题与 big.js 的作用 |
2 | Big 实例的创建方式与最佳实践 |
3 | 常见运算方法及其使用方式 |
4 | 比较操作符的替代方法 |
5 | 格式化输出与舍入设置 |
6 | big.js 与 decimal.js 的对比 |
7 | 框架集成与工具封装 |
8 | 性能优化技巧 |
9 | 错误处理与输入验证 |
10 | 安全构建实例的方法 |
如果你正在开发一个 Vue/React 商业系统,强烈建议你在涉及金额、汇率、折扣、库存等关键业务逻辑中使用 big.js
来保障计算精度和数据准确性。
老曹建议将 big.js
工具函数统一放在 /utils/financial.js
中,并在需要的地方按需引入。