数值千分位就是把 987654321.02 这种转换为 987,654,321.02 这种形式
1、数组转字符串遍历拼接
- 数字转字符串,并按照 . 分割
- 整数部分拆分成字符串数组:类似
[9, 3, 8, 7, 6, 5, 4, 3, 2] - 遍历,按照每 3 位添加 , 号
- 拼接整数部分 + 小数部分
/**
* 将数字格式化为千位分隔符的形式
* @param number 要格式化的数字
* @returns 格式化后的字符串
*/
function format(number) {
// 将数字转为字符串,并按照小数点拆分
const [int, fraction] = String(number).split('.')
// 将整数部分拆分为数组
const intArr = int.split('')
let res = ''
// 遍历整数部分的数组
intArr.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 [int, fraction] = String(number).split('.')
// 计算整数部分多余的位数
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 mod
let r = ''
// 循环处理整数部分
do {
// 获取后三位,可能有小数
mod = n % 1000
// 判断值是不是大于1,即三位数以上
n = n / 1000
// 相当于Math.floor() 去除小数部分
temp = ~~mod
// 如果 n >= 1 证明可千分位,在之前 % 1000 的时候 1001 会变成 1,所以需要使用 padStart 补0
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) {
const strNumber = String(number)
const index = strNumber.indexOf('.')
let intStr = strNumber
let fractionStr = ''
// 处理整数部分
if (index >= 0) {
intStr = strNumber.substring(0, index)
fractionStr = strNumber.substring(index)
}
// 将整数部分按照千位分隔符格式化
let r = ''
const reg = /\d{1,3}(?=(\d{3})+$)/g
r = intStr.replace(reg, '$&,')
return r + fractionStr
}
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 [int, fraction] = String(number).split('.')
const intArr = int.split('')
let res = ''
intArr.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 [int, fraction] = String(number).split('.')
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 mod
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 strNumber = String(number)
const index = strNumber.indexOf('.')
let intStr = strNumber
let fractionStr = ''
if (index >= 0) {
intStr = strNumber.substring(0, index)
fractionStr = strNumber.substring(index)
}
let r = ''
const reg = /\d{1,3}(?=(\d{3})+$)/g
r = intStr.replace(reg, '$&,')
return r + fractionStr
}
</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) {
const data = new Array(count).fill(0).map(function (i) {
const rd = Math.random()
let 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) {
const start = performance.now()
for (let i = 0; i < data.length; i++) {
fn(data[i])
}
const time = performance.now() - start
message((fn.name || label) + ':' + time.toFixed(2) + 'ms')
}
function executeTest() {
const 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) {
const el = document.createElement('p')
el.innerHTML = msg
messageEl.appendChild(el)
}
</script>
</body>
</html>