big.js與bignumber.js的差異、統(tǒng)一配置與避坑技巧完全指南
文檔地址
big.js文檔地址:https://mikemcl.github.io/big.js/
bignumber.js文檔地址:https://mikemcl.github.io/bignumber.js/
在前端高精度數(shù)值計(jì)算(如金額、金融場景)中,big.js 和 bignumber.js 是兩款主流工具庫(均由同一作者開發(fā))。但二者默認(rèn)行為的差異的可能導(dǎo)致跨項(xiàng)目計(jì)算結(jié)果不一致,且非法值 / 邊界值易觸發(fā)報(bào)錯(cuò)。本文將系統(tǒng)梳理核心差異、給出統(tǒng)一配置方案,并詳解非法值處理技巧,確保不同項(xiàng)目使用不同庫時(shí)邏輯一致、運(yùn)行穩(wěn)定。
一、核心默認(rèn)差異(聚焦關(guān)鍵項(xiàng))
兩款庫的定位和默認(rèn)配置差異直接影響計(jì)算邏輯,核心區(qū)別如下表:
配置項(xiàng) | big.js(默認(rèn)) | bignumber.js(默認(rèn)) | 影響說明 |
小數(shù)精度限制 | 無限制(保留完整計(jì)算結(jié)果) | 20 位(超出自動(dòng)舍入) | 無限小數(shù)運(yùn)算(如 1/3)結(jié)果長度不同 |
舍入模式觸發(fā)時(shí)機(jī) | 僅手動(dòng)調(diào)用 .dp()/.toFixed() 觸發(fā) | 超出 20 位精度自動(dòng)觸發(fā) + 手動(dòng)觸發(fā) | 隱性舍入導(dǎo)致結(jié)果不一致 |
科學(xué)計(jì)數(shù)法 | 始終常規(guī)表示(無指數(shù)格式) | 指數(shù)≥21/≤-7 時(shí)自動(dòng)切換科學(xué)計(jì)數(shù)法 | 數(shù)值顯示格式差異,影響序列化 |
特殊值處理 | 不支持 NaN/Infinity,非法值直接報(bào)錯(cuò) | 支持 NaN/Infinity,默認(rèn)返回 NaN | 錯(cuò)誤處理邏輯不同,易導(dǎo)致項(xiàng)目崩潰 |
舍入模式(默認(rèn)) | ROUND_HALF_UP(四舍五入) | ROUND_HALF_UP(四舍五入) | 核心規(guī)則一致,但觸發(fā)條件不同 |
關(guān)鍵差異拆解:舍入規(guī)則的 “隱性不一致”
二者默認(rèn)舍入模式均為「四舍五入」,但觸發(fā)邏輯不同:
- big.js:1/3 會返回?zé)o限循環(huán)的 0.3333333333333333...,僅手動(dòng)設(shè)置小數(shù)位時(shí)才舍入;
- bignumber.js:1/3 會自動(dòng)截?cái)酁?20 位 0.33333333333333333333,無需手動(dòng)觸發(fā)。
二、統(tǒng)一配置方案(跨項(xiàng)目一致性核心)
通過全局配置讓兩款庫遵循同一套規(guī)則,確保計(jì)算結(jié)果、顯示格式、錯(cuò)誤處理完全一致。
1. 全局統(tǒng)一配置代碼
// 引入庫
import Big from 'big.js';
import BigNumber from 'bignumber.js';
// --------------------------
// big.js 配置(對齊核心規(guī)則)
// --------------------------
Big.DP = 20; // 小數(shù)位上限設(shè)為20(匹配bignumber.js默認(rèn))
Big.RM = Big.roundHalfUp; // 顯式指定四舍五入(默認(rèn)值,可省略)
Big.EXP = 0; // 禁用科學(xué)計(jì)數(shù)法,始終常規(guī)顯示
Big.PE = 0; // 精度誤差閾值(默認(rèn)0,無需改)
// --------------------------
// bignumber.js 配置(對齊big.js嚴(yán)格性)
// --------------------------
BigNumber.config({
DECIMAL_PLACES: 20, // 小數(shù)位上限20
ROUNDING_MODE: BigNumber.ROUND_HALF_UP, // 四舍五入
EXPONENTIAL_AT: [-Infinity, Infinity], // 禁用科學(xué)計(jì)數(shù)法
ALLOW_NAN: false, // 禁用NaN,非法值直接報(bào)錯(cuò)(匹配big.js)
ALLOW_INFINITY: false, // 禁用Infinity,匹配big.js
PRECISION: 20, // 有效數(shù)字精度20(與DECIMAL_PLACES配合)
});2. 一致性驗(yàn)證 Demo
場景 1:常規(guī)四舍五入(保留 2 位小數(shù))
const num = '1.235'; // 經(jīng)典四舍五入場景 // big.js 計(jì)算 const bigResult = new Big(num).dp(2, Big.roundHalfUp).toString(); // 結(jié)果:"1.24" // bignumber.js 計(jì)算 const bnResult = new BigNumber(num).decimalPlaces(2, BigNumber.ROUND_HALF_UP).toString(); // 結(jié)果:"1.24"(與big.js一致)
場景 2:無限小數(shù)運(yùn)算(1/3)
const divisor = '3';
// big.js 計(jì)算(手動(dòng)指定20位小數(shù))
const bigDiv = new Big('1').div(divisor).dp(20, Big.roundHalfUp).toString();
// 結(jié)果:"0.33333333333333333333"
// bignumber.js 計(jì)算(自動(dòng)截?cái)?手動(dòng)確認(rèn))
const bnDiv = new BigNumber('1').div(divisor).decimalPlaces(20, BigNumber.ROUND_HALF_UP).toString();
// 結(jié)果:"0.33333333333333333333"(與big.js一致)場景 3:大數(shù)顯示(禁用科學(xué)計(jì)數(shù)法)
const bigNum = '1000000000000000000000'; // 1e21 // big.js 顯示 new Big(bigNum).toString(); // "1000000000000000000000" // bignumber.js 顯示(配置后) new BigNumber(bigNum).toString(); // "1000000000000000000000"(無科學(xué)計(jì)數(shù)法)
三、非法值 / 邊界值處理(避坑核心)
非法值(如非數(shù)字字符串、空值)或邊界值(如超大數(shù)、0/0 運(yùn)算)易觸發(fā)報(bào)錯(cuò),需通過「前置校驗(yàn) + 異常捕獲」規(guī)避。
1. 通用工具函數(shù)(統(tǒng)一適配兩款庫)
/**
* 校驗(yàn)數(shù)值是否為合法的可轉(zhuǎn)換數(shù)字
* @param {*} value 輸入值
* @returns {boolean} 是否合法
*/
function isValidNumber(value) {
// 排除空值、非字符串/數(shù)字類型
if (value === null || value === undefined || typeof value === 'boolean') {
return false
}
// 轉(zhuǎn)字符串后去除首尾空格,排除空字符串
const strValue = String(value).trim()
if (strValue === '') {
return false
}
// 正則校驗(yàn):僅允許數(shù)字、小數(shù)點(diǎn)(最多一個(gè))、正負(fù)號(僅開頭)
const numReg = /^[-+]?(\d+(\.\d*)?|\.\d+)$/
if (!numReg.test(strValue)) {
return false
}
// 校驗(yàn)極值:避免超出安全范圍(可根據(jù)業(yè)務(wù)調(diào)整)
const num = Number(strValue)
if (isNaN(num) || !isFinite(num)) {
return false
}
return true
}
/**
* 安全創(chuàng)建 Big/bignumber 實(shí)例
* @param {*} value 輸入值
* @param {string} lib 庫類型:'big.js' | 'bignumber.js'
* @returns {Big | BigNumber | null} 實(shí)例或null(失敗時(shí))
*/
function safeCreateInstance(value, lib = 'big.js') {
try {
if (!isValidNumber(value)) {
console.warn(`非法值:${value},無法轉(zhuǎn)換為高精度數(shù)字`)
return null
}
const strValue = String(value).trim()
return lib === 'big.js' ? new Big(strValue) : new BigNumber(strValue)
} catch (error) {
console.error(`創(chuàng)建高精度數(shù)字失?。?{error.message}`)
return null
}
}
/**
* 安全執(zhí)行高精度運(yùn)算(以加法為例)
* @param {*} a 第一個(gè)數(shù)
* @param {*} b 第二個(gè)數(shù)
* @param {string} lib 庫類型
* @returns {string | null} 運(yùn)算結(jié)果(字符串形式避免精度丟失)
*/
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:處理非數(shù)字字符串 / 空值
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 結(jié)果:', bigInstance || '非法值')
console.log('bignumber.js 結(jié)果:', bnInstance || '非法值')
})
// 輸出:所有非法值均返回"非法值",無報(bào)錯(cuò)Demo 2:處理極值 / 無效運(yùn)算
// 測試用例:超大數(shù)、0/0運(yùn)算
const extremeValues = ['1e+1000', '0.000000000000000000001', '0']
// 測試0/0(無效運(yùn)算)
const a = safeCreateInstance('0')
const b = safeCreateInstance('0')
try {
const result = a.div(b).toString()
} catch (error) {
console.error('無效運(yùn)算:', error.message) // 捕獲"Division by zero"錯(cuò)誤
}
// 測試超大數(shù)
const bigExtreme = safeCreateInstance('1e+1000', 'big.js')
if (bigExtreme) {
console.log('big.js 處理超大數(shù):', bigExtreme.dp(20).toString())
}四、使用注意點(diǎn)(關(guān)鍵避坑)
- 舍入模式擴(kuò)展:若需使用「銀行家舍入(ROUND_HALF_EVEN)」,需同步修改兩款庫配置(Big.RM = Big.roundHalfEven / ROUNDING_MODE: BigNumber.ROUND_HALF_EVEN)。
- 非法值校驗(yàn):必須通過 isValidNumber 前置校驗(yàn)輸入,避免傳入非數(shù)字、空值等導(dǎo)致報(bào)錯(cuò)。
- 結(jié)果序列化:運(yùn)算結(jié)果建議用 toString() 轉(zhuǎn)換為字符串存儲 / 傳輸,避免二次轉(zhuǎn)換丟失精度。
- 體積與性能:big.js(4KB)比 bignumber.js(12KB)更輕量,簡單運(yùn)算場景優(yōu)先選 big.js;復(fù)雜場景(進(jìn)制轉(zhuǎn)換、格式化)選 bignumber.js。
- 局部配置優(yōu)先級:全局配置后,單次運(yùn)算可通過方法參數(shù)覆蓋(如 dp(6, Big.roundDown)),適合特殊場景。
總結(jié)
big.js 和 bignumber.js 實(shí)現(xiàn)跨項(xiàng)目一致性的核心是「統(tǒng)一配置 + 統(tǒng)一校驗(yàn)」:
- 統(tǒng)一小數(shù)精度、舍入模式、顯示格式,消除默認(rèn)差異;
- 通過前置校驗(yàn) + 異常捕獲,處理非法值 / 邊界值,避免報(bào)錯(cuò);
- 運(yùn)算結(jié)果以字符串形式輸出,確保序列化一致性。
實(shí)際開發(fā)中,可根據(jù)項(xiàng)目體積需求選擇庫(輕量選 big.js,復(fù)雜選 bignumber.js),但需嚴(yán)格遵循本文的統(tǒng)一配置和校驗(yàn)邏輯,確保不同項(xiàng)目計(jì)算結(jié)果完全一致。
到此這篇關(guān)于big.js與bignumber.js的差異、統(tǒng)一配置與避坑技巧的文章就介紹到這了,更多相關(guān)big.js與bignumber.js指南內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS來動(dòng)態(tài)的修改url實(shí)現(xiàn)對url的增刪查改
通過get方式提交post表單等方式來動(dòng)態(tài)修改url存在諸多的不妥,因此,想到了通過JS來動(dòng)態(tài)的修改url,來實(shí)現(xiàn)對url的增刪查改2014-09-09
cropper.js和exif.js實(shí)現(xiàn)頭像上傳縮放裁剪旋轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了cropper.js和exif.js實(shí)現(xiàn)頭像上傳縮放裁剪旋轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
javascript運(yùn)行機(jī)制之執(zhí)行順序理解
這篇文章主要介紹了javascript運(yùn)行機(jī)制之執(zhí)行順序理解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
基于JavaScript開發(fā)一個(gè)有趣的分組抽簽小程序
在團(tuán)隊(duì)合作開發(fā)中,經(jīng)常需要將團(tuán)隊(duì)成員分組,來完成各自的任務(wù),而抽簽的方式自然是最公平、最簡單的方法之一,所以本文就來開發(fā)一個(gè)有趣的分組抽簽小程序吧2023-05-05
百度UEditor編輯器如何關(guān)閉抓取遠(yuǎn)程圖片功能
這篇文章主要介紹了百度UEditor編輯器如何關(guān)閉抓取遠(yuǎn)程圖片功能,需要的朋友可以參考下2015-03-03
JavaScript實(shí)現(xiàn)左右點(diǎn)擊切換圖片
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡易左右點(diǎn)擊切換圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
淺談JS for循環(huán)中使用break和continue的區(qū)別
這篇文章主要介紹了淺談for循環(huán)中使用break和continue的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07

