big.js与bignumber.js的差异、统一配置与避坑技巧完全指南
作者:绝世唐门三哥
文档地址
big.js文档地址:https://mikemcl.github.io/big.js/
bignumber.js文档地址:https://mikemcl.github.io/bignumber.js/
在前端高精度数值计算(如金额、金融场景)中,big.js 和 bignumber.js 是两款主流工具库(均由同一作者开发)。但二者默认行为的差异的可能导致跨项目计算结果不一致,且非法值 / 边界值易触发报错。本文将系统梳理核心差异、给出统一配置方案,并详解非法值处理技巧,确保不同项目使用不同库时逻辑一致、运行稳定。
一、核心默认差异(聚焦关键项)
两款库的定位和默认配置差异直接影响计算逻辑,核心区别如下表:
配置项 | big.js(默认) | bignumber.js(默认) | 影响说明 |
小数精度限制 | 无限制(保留完整计算结果) | 20 位(超出自动舍入) | 无限小数运算(如 1/3)结果长度不同 |
舍入模式触发时机 | 仅手动调用 .dp()/.toFixed() 触发 | 超出 20 位精度自动触发 + 手动触发 | 隐性舍入导致结果不一致 |
科学计数法 | 始终常规表示(无指数格式) | 指数≥21/≤-7 时自动切换科学计数法 | 数值显示格式差异,影响序列化 |
特殊值处理 | 不支持 NaN/Infinity,非法值直接报错 | 支持 NaN/Infinity,默认返回 NaN | 错误处理逻辑不同,易导致项目崩溃 |
舍入模式(默认) | ROUND_HALF_UP(四舍五入) | ROUND_HALF_UP(四舍五入) | 核心规则一致,但触发条件不同 |
关键差异拆解:舍入规则的 “隐性不一致”
二者默认舍入模式均为「四舍五入」,但触发逻辑不同:
- big.js:1/3 会返回无限循环的 0.3333333333333333...,仅手动设置小数位时才舍入;
- bignumber.js:1/3 会自动截断为 20 位 0.33333333333333333333,无需手动触发。
二、统一配置方案(跨项目一致性核心)
通过全局配置让两款库遵循同一套规则,确保计算结果、显示格式、错误处理完全一致。
1. 全局统一配置代码
// 引入库
import Big from 'big.js';
import BigNumber from 'bignumber.js';
// --------------------------
// big.js 配置(对齐核心规则)
// --------------------------
Big.DP = 20; // 小数位上限设为20(匹配bignumber.js默认)
Big.RM = Big.roundHalfUp; // 显式指定四舍五入(默认值,可省略)
Big.EXP = 0; // 禁用科学计数法,始终常规显示
Big.PE = 0; // 精度误差阈值(默认0,无需改)
// --------------------------
// bignumber.js 配置(对齐big.js严格性)
// --------------------------
BigNumber.config({
DECIMAL_PLACES: 20, // 小数位上限20
ROUNDING_MODE: BigNumber.ROUND_HALF_UP, // 四舍五入
EXPONENTIAL_AT: [-Infinity, Infinity], // 禁用科学计数法
ALLOW_NAN: false, // 禁用NaN,非法值直接报错(匹配big.js)
ALLOW_INFINITY: false, // 禁用Infinity,匹配big.js
PRECISION: 20, // 有效数字精度20(与DECIMAL_PLACES配合)
});2. 一致性验证 Demo
场景 1:常规四舍五入(保留 2 位小数)
const num = '1.235'; // 经典四舍五入场景 // big.js 计算 const bigResult = new Big(num).dp(2, Big.roundHalfUp).toString(); // 结果:"1.24" // bignumber.js 计算 const bnResult = new BigNumber(num).decimalPlaces(2, BigNumber.ROUND_HALF_UP).toString(); // 结果:"1.24"(与big.js一致)
场景 2:无限小数运算(1/3)
const divisor = '3';
// big.js 计算(手动指定20位小数)
const bigDiv = new Big('1').div(divisor).dp(20, Big.roundHalfUp).toString();
// 结果:"0.33333333333333333333"
// bignumber.js 计算(自动截断+手动确认)
const bnDiv = new BigNumber('1').div(divisor).decimalPlaces(20, BigNumber.ROUND_HALF_UP).toString();
// 结果:"0.33333333333333333333"(与big.js一致)场景 3:大数显示(禁用科学计数法)
const bigNum = '1000000000000000000000'; // 1e21 // big.js 显示 new Big(bigNum).toString(); // "1000000000000000000000" // bignumber.js 显示(配置后) new BigNumber(bigNum).toString(); // "1000000000000000000000"(无科学计数法)
三、非法值 / 边界值处理(避坑核心)
非法值(如非数字字符串、空值)或边界值(如超大数、0/0 运算)易触发报错,需通过「前置校验 + 异常捕获」规避。
1. 通用工具函数(统一适配两款库)
/**
* 校验数值是否为合法的可转换数字
* @param {*} value 输入值
* @returns {boolean} 是否合法
*/
function isValidNumber(value) {
// 排除空值、非字符串/数字类型
if (value === null || value === undefined || typeof value === 'boolean') {
return false
}
// 转字符串后去除首尾空格,排除空字符串
const strValue = String(value).trim()
if (strValue === '') {
return false
}
// 正则校验:仅允许数字、小数点(最多一个)、正负号(仅开头)
const numReg = /^[-+]?(\d+(\.\d*)?|\.\d+)$/
if (!numReg.test(strValue)) {
return false
}
// 校验极值:避免超出安全范围(可根据业务调整)
const num = Number(strValue)
if (isNaN(num) || !isFinite(num)) {
return false
}
return true
}
/**
* 安全创建 Big/bignumber 实例
* @param {*} value 输入值
* @param {string} lib 库类型:'big.js' | 'bignumber.js'
* @returns {Big | BigNumber | null} 实例或null(失败时)
*/
function safeCreateInstance(value, lib = 'big.js') {
try {
if (!isValidNumber(value)) {
console.warn(`非法值:${value},无法转换为高精度数字`)
return null
}
const strValue = String(value).trim()
return lib === 'big.js' ? new Big(strValue) : new BigNumber(strValue)
} catch (error) {
console.error(`创建高精度数字失败:${error.message}`)
return null
}
}
/**
* 安全执行高精度运算(以加法为例)
* @param {*} a 第一个数
* @param {*} b 第二个数
* @param {string} lib 库类型
* @returns {string | null} 运算结果(字符串形式避免精度丢失)
*/
function safeAdd(a, b, lib = 'big.js') {
const numA = safeCreateInstance(a, lib)
const numB = safeCreateInstance(b, lib)
if (!numA || !numB) return null
return numA.plus(numB).toString()
}2. 避坑 Demo 示例
Demo 1:处理非数字字符串 / 空值
const invalidValues = ['abc', '123a', '', null, undefined, true]
invalidValues.forEach((value) => {
const bigInstance = safeCreateInstance(value, 'big.js')
const bnInstance = safeCreateInstance(value, 'bignumber.js')
console.log(`输入:${value}`)
console.log('big.js 结果:', bigInstance || '非法值')
console.log('bignumber.js 结果:', bnInstance || '非法值')
})
// 输出:所有非法值均返回"非法值",无报错Demo 2:处理极值 / 无效运算
// 测试用例:超大数、0/0运算
const extremeValues = ['1e+1000', '0.000000000000000000001', '0']
// 测试0/0(无效运算)
const a = safeCreateInstance('0')
const b = safeCreateInstance('0')
try {
const result = a.div(b).toString()
} catch (error) {
console.error('无效运算:', error.message) // 捕获"Division by zero"错误
}
// 测试超大数
const bigExtreme = safeCreateInstance('1e+1000', 'big.js')
if (bigExtreme) {
console.log('big.js 处理超大数:', bigExtreme.dp(20).toString())
}四、使用注意点(关键避坑)
- 舍入模式扩展:若需使用「银行家舍入(ROUND_HALF_EVEN)」,需同步修改两款库配置(Big.RM = Big.roundHalfEven / ROUNDING_MODE: BigNumber.ROUND_HALF_EVEN)。
- 非法值校验:必须通过 isValidNumber 前置校验输入,避免传入非数字、空值等导致报错。
- 结果序列化:运算结果建议用 toString() 转换为字符串存储 / 传输,避免二次转换丢失精度。
- 体积与性能:big.js(4KB)比 bignumber.js(12KB)更轻量,简单运算场景优先选 big.js;复杂场景(进制转换、格式化)选 bignumber.js。
- 局部配置优先级:全局配置后,单次运算可通过方法参数覆盖(如 dp(6, Big.roundDown)),适合特殊场景。
总结
big.js 和 bignumber.js 实现跨项目一致性的核心是「统一配置 + 统一校验」:
- 统一小数精度、舍入模式、显示格式,消除默认差异;
- 通过前置校验 + 异常捕获,处理非法值 / 边界值,避免报错;
- 运算结果以字符串形式输出,确保序列化一致性。
实际开发中,可根据项目体积需求选择库(轻量选 big.js,复杂选 bignumber.js),但需严格遵循本文的统一配置和校验逻辑,确保不同项目计算结果完全一致。
到此这篇关于big.js与bignumber.js的差异、统一配置与避坑技巧的文章就介绍到这了,更多相关big.js与bignumber.js指南内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
