做報表的時候偶爾會遇到這種需求:
為了補齊長度,在一個數字字符串前面添加 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 是如何實現的...
如果有小伙伴知道原因,請一定給我留言,或者來一發傳送門,拜謝~
