功能: 可实现不同符号分隔数字, 可自定义分隔后数字保留的小数位数
实现思路
使用正则, 用数字中的小数点做匹配尾部参考, 来匹配某个数字后面的一个或多个连续 3 位数字, 如果匹配到把该数字替换成自身加分隔符, 如下:
示例
1 分隔数字: 123456.1
解释: 3 和. 之间有一个连续 3 位数字(456), 那么给 3 后面添加一个分隔符得到结果: 123,456.1
2 分隔数字: 1234567.1
解释: 1 和. 之间有两个连续 3 位数字(234 和 567), 那么给 1 后面添加一个分隔符, 然后数字 4 后面也存在一个连续三位数字(567), 那么也给 4 后面添加一个分隔符, 最终得到结果 1,234,567.1
匹配的正则表达式
/(\d)(?=(\d{3})+\.)/g;
这里最难理解的就是(?=(\d{3})+\.), 且看语法:
x(?=y): 正向肯定查找, 匹配后面带有 y 的 x 项目
那么在这里意思是: 查找一个和. 之间带有一个或多个连续 3 位数字的数字(x)
最终实现
/**
*num 要分隔的数字(必填)
*n 保留的小数位数(可选)
*symbol 分隔数字使用的符号(可选, 默认为 ",")
*/
function splitNum(num, n, symbol) {
if (!num) throw new Error('splitNum 需要传入一个待转换的数据');
if (typeof num !== 'number') throw new TypeError('num 参数应该是一个 number 类型');
if (n < 0) throw new Error('参数 n 不应该小于 0');
var hasDot = parseInt(num) != num; // 这里检测 num 是否为小数, true 表示小数
var m = (n != undefined && n != null) ? n: 1;
num = m == 0 ? num.toFixed(m) + '.': hasDot ? (n ? num.toFixed(n) : num) : num.toFixed(m);
symbol = symbol || ',';
num = num.toString().replace(/(\d)(?=(\d{3})+\.)/g,
function(match, p1, p2) {
return p1 + symbol;
});
if (n == 0 || (!hasDot && !n)) { // 如果 n 为 0 或者传入的 num 是整数并且没有指定整数的保留位数, 则去掉前面操作中的小数位
num = num.substring(0, num.indexOf('.'));
}
return num;
}
难点解惑
1 也许有人会问, 这里是用. 号做参考进行匹配的, 如果传进来的数字是一个整数呢, 不就没. 号了吗, 所以在方法内部定义了 m 变量使其在操作过程中总能有个. 号
2num = m == 0 ? num.toFixed(m) + '.': hasDot ? (n ? num.toFixed(n) : num) : num.toFixed(m);
num = m == 0 ? num.toFixed(m) + '.': hasDot ? (n ? num.toFixed(n) : num) : num.toFixed(m);
作用: 这里的操作保证的是小数传 n 小数不传 n 整数传 n 整数不传 n 四种情况都能正确返回小数位数
详解:
1 如果 m 为零 (传入 n=0) 则直接经 toFixed 操作后再后面补.
2 如果 m 不为 0,
a 如果传入数为小数
a'如果传了 n 表示要保留小数, 那么需要 num.toFixed(n)
b'如果没传 n 表示不需要对小数进行操作, 直接返回原 num
b 如果传入数为整数
a'直接对 num 进行 toFixed(m)操作
说明: 该方法只适用于常用数字的操作, 当数字超过一定位数时产生的精度问题这里暂不做处理
自己写的方法, 如果有什么不足之处欢迎指出交流, 这里的 replace 方法可参考我的另一篇文章
来源: https://juejin.im/post/5a72c6ebf265da3e5b33229d