JS 数值千分位的 6 种方法 & 性能对比
数值千分位就是把 987654321.02
这种转换为 987,654,321.02
这种形式
1、数组转字符串遍历拼接
- 数字转字符串,并按照 . 分割
- 整数部分拆分成字符串数组:类似
[9, 3, 8, 7, 6, 5, 4, 3, 2]
- 遍历,按照每 3 位添加 , 号
- 拼接整数部分 + 小数部分
function format(number) {
// 转为字符串,并按照 . 拆分
const arr = String(number).split(".");
// 整数拆分
const int = arr[0].split("");
// 小数
const fraction = arr[1] || "";
let res = "";
int.forEach((item, index) => {
// 非第一位且是 3 的倍数,添加 ","
if (index !== 0 && index % 3 === 0) {
res = res + "," + item;
} else {
// 正常添加字符
res = res + item;
}
});
// 整数和小数拼接
return res + (!!fraction ? `.${fraction}` : "");
}
console.log(format(987654321.02)); // 987,654,321.02
2、字符串+ substring截取
- 数字转字符串,并按照 . 分割
- 整数部分对3求模,获取多余部分
- 按照3截取 ,并添加 ,
- 拼接整数部分 + 小数部分
function format(number) {
const arr = String(number).split(".");
const int = arr[0];
const fraction = arr[1] || "";
// 多余的位数
const f = int.length % 3;
// 截取多余的位数
let res = int.substring(0, f);
// 每三位添加 , 和对应的字符
for (let i = 0; i < Math.floor(int.length / 3); i++) {
res += "," + int.substring(f + i * 3, f + (i + 1) * 3);
}
// 没有多余的位数则截取最前面的 ,
if (f === 0) {
res = res.substring(1);
}
return res + (!!fraction ? `.${fraction}` : "");
}
console.log(format(987654321.02)); // 987,654,321.02
3、除法 + 求模
- 值对 1000 求模,获得最高三位
- 值除以 1000,值是否大于 1 判定是否结束
- 重复1、2步,直到退出循环
- 拼接整数部分 + 小数部分
function format(number) {
let n = number;
let temp;
let r = "";
do {
// 求模的值,用于获取高三位,这里可能有小数
mod = n % 1000;
// 值是不是大于1,是继续的条件
n = n / 1000;
// 高三位
temp = ~~mod;
// 1. 填充 : n>1 循环未结束, 就要填充为比如,1 => 001,
// 不然 1 001, 就会变成 '11',
// 2. 拼接 ","
r = (n >= 1 ? `${temp}`.padStart(3, "0") : temp) + (!!r ? "," + r : "");
} while (n >= 1);
const strNumber = String(number);
const index = strNumber.indexOf(".");
// 拼接小数部分
if (index >= 0) {
r += strNumber.substring(index);
}
return r;
}
console.log(format(987654321.02)); // 987,654,321.02
4、正则先行断言
// 断言前面是 hello ,后面是 a-z
console.log(/hello (?=[a-z]+)/.test("hello a")); // true
console.log(/hello (?=[a-z]+)/.test("hello 1")); // false
// 方式一:
function format(number) {
// 三位数字进行分组,查找前面有 1 到 3 位的数字
const reg = /\d{1,3}(?=(\d{3})+$)/g;
// $&, 也可换成 $1, 表示被匹配到的内容
return String(number).replace(reg, "$&,");
}
// 方式二:
function format(number) {
const reg = /\d{1,3}(?=(\d{3})+$)/g;
// match 为匹配之后的内容
return String(number).replace(reg, function (match) {
return match + ",";
});
}
// 此方法不能处理小数
console.log(format(987654321)); // 987,654,321
5、Intl.NumberFormat
- 基本功能:国际化的数字处理方案,它可以用来显示不同国家对数字的处理偏好
- 属于国际化 API 规范:
ECMA-402
- 语法:
new Intl.NumberFormat([locales[, options]])
// 方式一:设置初始参数,性能较差
function format(number, minimumFractionDigits, maximumFractionDigits) {
minimumFractionDigits = minimumFractionDigits || 2;
maximumFractionDigits = maximumFractionDigits || 2;
maximumFractionDigits = Math.max(minimumFractionDigits, maximumFractionDigits);
return new Intl.NumberFormat("en-us", {
maximumFractionDigits: maximumFractionDigits || 2,
minimumFractionDigits: minimumFractionDigits || 2
}).format(number);
}
// 方式二:默认配置选项
function format(number) {
return new Intl.NumberFormat("en-us").format(number);
}
console.log(format(987654321.02)); // 987,654,321.02
6、toLocalString
- 功能:其能把数字转为特定语言环境下的表示字符串
- 底层调用
Intl.NumberFormat
- 语法:
numObj.toLocaleString([locales [, options]])
// 方式一:
function format(number, minimumFractionDigits, maximumFractionDigits) {
minimumFractionDigits = minimumFractionDigits || 2;
maximumFractionDigits = maximumFractionDigits || 2;
maximumFractionDigits = Math.max(minimumFractionDigits, maximumFractionDigits);
return number.toLocaleString("en-us", {
maximumFractionDigits: maximumFractionDigits || 2,
minimumFractionDigits: minimumFractionDigits || 2
});
}
// 方式二:
function format(number) {
return number.toLocaleString("en-us");
}
console.log(format(987654321.02)); // 987,654,321.02
性能比拼
这里测试了一万条数据,可以看出 除法+ 求模位运算 是其中最高效的方式
<!DOCTYPE html>
<html>
<body>
<div style="text-align: center">
<p><input type="number" value="5000" id="textCount" /></p>
<p>
<input type="button" onclick="executeTest()" value="测试" />
<input
type="button"
onclick="javascript:document.getElementById('messageEl').innerHTML=''"
value="清除"
/>
</p>
</div>
<div id="messageEl" style="width: 300px; margin: auto"></div>
<script>
function format_with_array(number) {
const arr = String(number).split(".");
const int = arr[0].split("");
const fraction = arr[1] || "";
let res = "";
int.forEach((item, index) => {
if (index !== 0 && index % 3 === 0) {
res = res + "," + item;
} else {
res = res + item;
}
});
return res + (!!fraction ? `.${fraction}` : "");
}
</script>
<script>
function format_with_substring(number) {
const arr = String(number).split(".");
const int = arr[0];
const fraction = arr[1] || "";
const f = int.length % 3;
let res = int.substring(0, f);
for (let i = 0; i < Math.floor(int.length / 3); i++) {
res += "," + int.substring(f + i * 3, f + (i + 1) * 3);
}
if (f === 0) {
res = res.substring(1);
}
return res + (!!fraction ? `.${fraction}` : "");
}
</script>
<script>
function format_with_mod(number) {
let n = number;
let temp;
let r = "";
do {
mod = n % 1000;
n = n / 1000;
temp = ~~mod;
r = (n >= 1 ? `${temp}`.padStart(3, "0") : temp) + (!!r ? "," + r : "");
} while (n >= 1);
const strNumber = String(number);
const index = strNumber.indexOf(".");
if (index >= 0) {
r += strNumber.substring(index);
}
return r;
}
</script>
<script>
function format_with_regex(number) {
const reg = /(\d{1,3})(?=(\d{3})+(?:$|.))/g;
return (number + "").replace(reg, "$1,");
}
</script>
<script>
// function format_with_toLocaleString(number, minimumFractionDigits, maximumFractionDigits) {
// minimumFractionDigits = minimumFractionDigits || 2;
// maximumFractionDigits = (maximumFractionDigits || 2);
// maximumFractionDigits = Math.max(minimumFractionDigits, maximumFractionDigits);
// return number.toLocaleString("en-us", {
// maximumFractionDigits: maximumFractionDigits || 2,
// minimumFractionDigits: minimumFractionDigits || 2
// })
// }
function format_with_toLocaleString(number) {
return number.toLocaleString("en-us");
}
</script>
<script>
// function format_with_Intl(number, minimumFractionDigits, maximumFractionDigits) {
// minimumFractionDigits = minimumFractionDigits || 2;
// maximumFractionDigits = (maximumFractionDigits || 2);
// maximumFractionDigits = Math.max(minimumFractionDigits, maximumFractionDigits);
// return new Intl.NumberFormat('en-us', {
// maximumFractionDigits: maximumFractionDigits || 2,
// minimumFractionDigits: minimumFractionDigits || 2
// }).format(number)
// }
const format = new Intl.NumberFormat("en-us");
function format_with_Intl(number) {
return format.format(number);
}
</script>
<script>
function getData(count) {
var data = new Array(count).fill(0).map(function (i) {
var rd = Math.random();
var r = rd * Math.pow(10, Math.trunc(Math.random() * 12));
if (rd > 0.5) {
r = ~~r;
}
return r;
});
return data;
}
function test(data, fn, label) {
var start = performance.now();
for (var i = 0; i < data.length; i++) {
fn(data[i]);
}
var time = performance.now() - start;
message((fn.name || label) + ":" + time.toFixed(2) + "ms");
}
function executeTest() {
var data = getData(+textCount.value);
test(data, format_with_array);
test(data, format_with_mod);
test(data, format_with_substring);
test(data, format_with_regex);
test(data, format_with_toLocaleString);
test(data, format_with_Intl);
message("-------------------");
}
function message(msg) {
var el = document.createElement("p");
el.innerHTML = msg;
messageEl.appendChild(el);
}
</script>
</body>
</html>
转载自:https://juejin.cn/post/7201838656894746683