前端开发【工具函数】基于number-precision 封装的NumberUtils工具函数,可以直接拿着使用

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位小数,如 100010.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
    // 确定单位层级(如 100001万,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亿"
  },
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的沙粒

您的鼓励是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值