Talk is cheap. Show me your code

添零占位 —— 快速生成N个0的六种办法

做报表的时候偶尔会遇到这种需求:

为了补齐长度,在一个数字字符串前面添加 N 个 0 占位

举个例子:

单元格需要展示 6 位数字,如 '123456'

但后端返回的数字是 123,这时候就要在前面补 0,得到 '000123',使其长度为 6

那就需要实现一个方法,基于 number 类型的参数 n,返回由 n 个 0 组成的字符串

 

以及,在众多方案中,哪一个方案的耗时最短?

 

测试模板:

// pad_start.js

function getPlaceholder(n, mark = '0') {
  // ...
}

function padStart(num, len) {
  const length = len - String(num).length;
  return length > 0 ? `${getPlaceholder(length)}${num}` : `${num}`;
}

console.time("Running");
const str = padStart(123, 10000000);
console.log('字符长度:', str.length.toLocaleString());
console.timeEnd("Running");

在模板代码中,需要实现 getPlaceholder 方法来添零占位,然后统计补全千万长度的数字需要多少时间

 

方案一:for 循环

function getPlaceholder(n, mark = '0') {
    let str = '';
    for (let i = 0; i < n; i++) {
        str += mark;
    }
    return str;
}

作为兜底方案,for 循环可能会迟到,但从不缺席...

  

方案二:Math.pow

function getPlaceholder(n) {
    return Math.pow(10, n).toString().slice(1);
}

由于需求是添“0”占位,可以取个巧,通过 Math.pow() 生成 10 的倍数,然后删掉首位的“1”,就得到了一串“0”

不过如果数值过大,JS 会使用科学计数法,所以这里最健壮的写法应该是:

function getPlaceholder(n) {
    return Math.pow(10, n).toLocaleString('zh-CN').replace(/,/g, '').slice(1);
}

即便如此,由于 JS 存在数值上限 Number.MAX_VALUE,所以 Math.pow(10, 309) 的结果为 Infinity,当字符长度超过 308 时就无法使用该方案

这种方案的局限性太大,除了上面说的情况以外,如果需要使用“0”以外的占位符就用不了

所以就不对该方案测速了...

 

方案三:Number.toFixed

function getPlaceholder(n) {
    return (1).toFixed(n).replace('.', '').slice(1);
}

如果对一个整数调用 toFixed,小数点后会用 0 来补位。基于这个特性可以很方便的生成一串“0”

和方案二类似,这种方案只适用于用“0”占位的场景

而且 toFixed 的入参只能是 0 ~ 100 的数字,无法处理超长的字符串,所以也不测速了...

 

方案四:Array.fill

function getPlaceholder(n, mark = '0') {
    return Array(n).fill('0').join('');
}

生成一个长度为 n 的数组,然后将元素都设为“0”,最后通过 join 拼成字符串

比较全面的方案,相对简洁,也可以自定义占位符

除了 Array.fill 之外,还可以使用其他方法,如 Array.from、Array.map

这种方案的速度就快多了,比 for 循环节省了近六成的时间

  

方案五:Array.join

function getPlaceholder(n, mark = '0') {
    return Array(n + 1).join(mark);
}

方案四的进化版,new Array 之后会生成由 empty 构成的数组,可以直接对该数组做 join

有一点需要注意,生成的数组长度得是 n + 1,因为 join 是对数组元素的间隙做填充

相比于方案四,少了一次 Array.fill(),所以速度明显提升

 

方案六:String.padStart

ES2017 新增的方法,可以直接完成字符串的填充,参考 MDN > padStart

const num = 123;
// 下面的 8 是总长度
String(num).padStart(8, "0");
// "00000123"

类似的还有 padEnd

 

对该方案的测试,需要稍微修改下测试模板的代码:

console.time("Running");
const str = String(123).padStart(10000000, "0");
console.log('字符长度:', str.length.toLocaleString());
console.timeEnd("Running");

这速度离谱吗?确实离谱!但这不是最离谱的...

 

我把字符长度从一千万逐步加到十亿,耗时居然没啥变化 ?!

可惜我翻遍了各种资料,也没查到如此高效的 String.padStart 是如何实现的...

如果有小伙伴知道原因,请一定给我留言,或者来一发传送门,拜谢~

 

posted @ 2021-10-11 17:44  Wise.Wrong  阅读(2352)  评论(0编辑  收藏  举报