number-precision 是解决 JavaScript 浮点数精度问题的轻量库(体积 < 2KB),基于它封装工具函数可覆盖「精度计算、格式转换、数值校验、金额处理」等高频场景,以下是完整工具文件及使用示例,可直接导入项目使用。
import NP from 'number-precision'
/**
* 基于 number-precision 的数字处理工具库
* 功能覆盖:精度计算、金额格式化、数值校验、单位转换、数据脱敏
* 依赖:npm install number-precision --save
*/
export const NumberUtils = {
// 1. 精度计算工具(解决浮点数加减乘除精度问题)============================================
/**
* 数字除法(支持多位数相除,如 divide(100, 2, 5) = 100÷2÷5)
* @param {Number|String} first - 被除数
* @param {Number|String} ...rest - 除数(支持多个,需确保除数不为0)
* @returns {Number} 相除结果(除数为0时返回0)
*/
divide(first, ...rest) {
if (first === undefined || first === null) return 0
const firstNum = Number(first)
const restNums = rest
.filter((item) => {
const num = Number(item)
return item !== undefined && item !== null && num !== 0 // 过滤0和非数字
})
.map(Number)
if (restNums.length === 0) return firstNum
// 多位数相除:从被除数开始,依次除以后续数
return restNums.reduce((total, curr) => NP.divide(total, curr), firstNum)
},
/**
* 数字四舍五入(指定小数位数)
* @param {Number|String} num - 待处理数字
* @param {Number} decimal - 保留小数位数(默认2位)
* @returns {Number} 四舍五入结果
*/
round(num, decimal = 2) {
if (num === undefined || num === null) return 0
const targetNum = Number(num)
return NP.round(targetNum, decimal)
},
// 2. 金额处理工具(财务场景专用)============================================
/**
* 金额格式化(分转元,保留2位小数,如 1000 → 10.00)
* @param {Number|String} cent - 以“分”为单位的金额(如 1000 分 = 10.00 元)
* @returns {String} 格式化后的金额字符串(如 "10.00")
*/
centToYuan(cent) {
if (cent === undefined || cent === null) return '0.00'
// 分转元:除以100,保留2位小数,转为字符串
const yuan = NP.divide(Number(cent), 100)
return yuan.toFixed(2) // 确保输出2位小数(如 10 → "10.00")
},
/**
* 金额千分位格式化(如 12345.67 → "12,345.67")
* @param {Number|String} amount - 金额(元为单位,支持整数/小数)
* @param {Number} decimal - 保留小数位数(默认2位)
* @returns {String} 千分位格式化后的金额字符串
*/
formatAmount(amount, decimal = 2) {
if (amount === undefined || amount === null) return '0.00'
// 先四舍五入到指定小数位,避免原数字小数位过长
const rounded = this.round(Number(amount), decimal)
// 分割整数部分和小数部分
const [integerPart, decimalPart = ''] = rounded.toString().split('.')
// 整数部分加千分位(正则匹配:从后往前每3位加逗号)
const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
// 补全小数位(不足指定位数补0,超出则截断)
const formattedDecimal = decimalPart.padEnd(decimal, '0').slice(0, decimal)
// 拼接结果(无小数位时不显示小数点)
return decimal > 0 ? `${formattedInteger}.${formattedDecimal}` : formattedInteger
},
/**
* 金额脱敏(如 12345.67 → "12,***.67",中间部分替换为*)
* @param {Number|String} amount - 金额(元为单位)
* @param {Number} keepStart - 保留开头位数(默认2位)
* @param {Number} keepEnd - 保留结尾位数(默认2位,小数部分)
* @returns {String} 脱敏后的金额字符串
*/
maskAmount(amount, keepStart = 2, keepEnd = 2) {
const formatted = this.formatAmount(amount, keepEnd)
const [integerPart, decimalPart = ''] = formatted.split('.')
// 处理整数部分脱敏
if (integerPart.length <= keepStart) {
// 整数部分长度不足保留位数,不脱敏
return formatted
}
const start = integerPart.slice(0, keepStart)
const mask = '*'.repeat(integerPart.length - keepStart)
const maskedInteger = `${start}${mask}`
// 拼接小数部分
return decimalPart ? `${maskedInteger}.${decimalPart}` : maskedInteger
},
// 3. 数值校验工具(判断数字合法性)============================================
/**
* 判断是否为有效数字(排除 NaN、Infinity、非数字字符串)
* @param {any} val - 待校验值
* @returns {Boolean} 是否为有效数字
*/
isNumber(val) {
const num = Number(val)
// 排除 NaN、Infinity、-Infinity,且原始值不为空字符串
return !isNaN(num) && isFinite(num) && val !== ''
},
/**
* 判断数字是否在指定范围内(包含边界)
* @param {Number|String} num - 待判断数字
* @param {Number|String} min - 最小值
* @param {Number|String} max - 最大值
* @returns {Boolean} 是否在范围内(非有效数字返回false)
*/
isInRange(num, min, max) {
if (!this.isNumber(num) || !this.isNumber(min) || !this.isNumber(max)) return false
const target = Number(num)
const minNum = Number(min)
const maxNum = Number(max)
return target >= minNum && target <= maxNum
},
/**
* 判断是否为整数(包含正整数、负整数、0)
* @param {Number|String} val - 待校验值
* @returns {Boolean} 是否为整数
*/
isInteger(val) {
if (!this.isNumber(val)) return false
const num = Number(val)
return Number.isInteger(num)
},
// 4. 单位转换工具(常见业务单位)============================================
/**
* 大数字单位转换(如 123456 → "12.35万",123456789 → "1.23亿")
* @param {Number|String} num - 待转换数字(支持整数/小数)
* @param {Number} decimal - 保留小数位数(默认2位)
* @returns {String} 带单位的数字字符串
*/
formatBigNumber(num, decimal = 2) {
if (!this.isNumber(num)) return '0'
const target = Number(num)
const units = ['', '万', '亿', '万亿'] // 单位层级
let unitIndex = 0
let result = target
// 确定单位层级(如 10000 → 1万,100000000 → 1亿)
while (result >= 10000 && unitIndex < units.length - 1) {
result = this.divide(result, 10000)
unitIndex++
}
// 四舍五入到指定小数位,拼接单位
const rounded = this.round(result, decimal)
return `${rounded}${units[unitIndex]}`
},
// 5. 使用示例(复制到组件中可直接测试)============================================
testNumberUtils() {
console.log('===== 精度计算示例 =====')
console.log(this.divide(100, 2, 5)) // 10(100÷2÷5)
console.log(this.round(123.456, 2)) // 123.46(四舍五入保留2位)
console.log('\n===== 金额处理示例 =====')
console.log(this.centToYuan(1234)) // "12.34"(1234分=12.34元)
console.log(this.formatAmount(12345.67)) // "12,345.67"(千分位格式化)
console.log(this.maskAmount(12345.67)) // "12,***.67"(金额脱敏)
console.log('\n===== 数值校验示例 =====')
console.log(this.isNumber('123.45')) // true(字符串数字视为有效)
console.log(this.isNumber('abc')) // false(非数字字符串)
console.log(this.isInRange(5, 0, 10)) // true(5在0-10范围内)
console.log(this.isInteger('123')) // true(字符串整数视为有效)
console.log('\n===== 单位转换示例 =====')
console.log(this.formatBigNumber(123456)) // "12.35万"(大数字转单位)
console.log(this.formatBigNumber(123456789)) // "1.23亿"
},
}
268

被折叠的 条评论
为什么被折叠?



