字符串 padStart(),padEnd()

557 阅读3分钟

这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

前言

ECMAScript 6.0 简称ES6 , 是 JavaScript 语言的新一代的标准,于在 2015 年 6 月发布,正式名称就是《ECMAScript 2015 标准》。一般情况,泛指, 5.1版以后的标准,涵盖了 ES2015、ES2016、ES2017、ES2018、ES2019、ES2020、ES2021 等等

我们一起来学习和自己实现:

  • String.prototype.padStart
  • String.prototype.padEnd

这两个都是字符串补全的方法,一个前面补全,一个后面补全。

String.prototype.padStart

使用一个字符串填充当前字符串,以便产生的字符串达到给定的长度。

语法

str.padStart(targetLength [, padString])

  • targetLength 需要保持的长度
  • padString 填充的字符串, 默认值为 " "

一起来看看经典应用:

日期填充

把日期转为 "yyyy-mm-dd"格式, 因为月和日可能小于10, 不足两位,之前主要是通过判断数字是都大于10来做填充,现在可就简单多了。

const date = new Date(2020,1,1);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const ddate = date.getDate();

const dateStr = year + "-" + 
(month + "").padStart(2, "0") + "-" 
+ (ddate + "").padStart(2, "0") 
// 2020-02-01

编码填充

我们把码点转为 二进制或者16进制等等, 因为我们一般是8个比特位一组。

低于0xFFFF码点的字符转为\uxxxx格式, 转为二进制也是类得的。

"\\u"  + "a".codePointAt(0).toString(16).padStart(4, "0")  // '\u0061'

特殊情况

长度值小于0

第一个参数长度都还好理解,毕竟嘛,如果小于0,负数,就以字符串的自身长度为准。

"a".padStart(0, "0")  // 'a'
"a".padStart(-10, "0") // 'a'

长度参数不是数字

如果第一个参数,不是数字呢? 可以猜想到,依旧是自身的长度为准。

"a".padStart(NaN, "0")  // 'a'
"a".padStart({}, "0")   // 'a'

填充字符

第二参数如果是undefined或者null

"a".padStart(5, undefined)  // '    a'
"a".padStart(5, null)       // 'nulla'

到这里,基本可以理解了,如果是undefined,就采用默认值 " ",不然就把其值转为字符串。

"a".padStart(5, {})  // '[obja' 这里还可以看出会截断
"a".padStart(5, 10.2)        // '10.2a'

这里,你可能还想想到 Symbol呢?

"a".padStart(5, Symbol.for("a")) 

截图_20211216111208.png

也许到这里,你觉得你懂了,我们再换一个

"a".padStart(5, [])  // 'a' 

哈哈,是不是有一点小惊喜。 这里因为 []转为字符串后是 ""字符串,如果填充字符是空字符串,是不会进行填充的。

基于ES5 Polyfill

思路当然是检查长度,如果不够,逐个添加。

当然更多的实现细节得参考 ES实现标准 StringPad

如下是MDN的实现:

if (!String.prototype.padStart) {
    String.prototype.padStart = function padStart(targetLength,padString) {        
        targetLength = targetLength >> 0;
        padString = typeof padString !== 'undefined' ? padString + '' : ' ');
        if (this.length > targetLength) {
            return String(this);
        }
        else {
            targetLength = targetLength - this.length;  
            if (targetLength > padString.length) {
                padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
            }
            return padString.slice(0,targetLength) + String(this);
        }
    };
}

这里有两个细节:

  1. targetLength >> 0
    通过位移获得数字,我们单独讲解。
  2. padString.repeat
    repeat也是ES6出现的,需要自己额外实现。

不借助repeat我们怎么实现呢? for循环,当然。

String.prototype.padEnd

与padStart非常类似,不做过多介绍。

"a".padEnd(4, "0") // 'a000'

MDN的Polyfill, 思路也非常的类似。

// https://github.com/uxitten/polyfill/blob/master/string.polyfill.js
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
if (!String.prototype.padEnd) {
    String.prototype.padEnd = function padEnd(targetLength,padString) {
        targetLength = targetLength>>0; //floor if number or convert non-number to 0;
        padString = String((typeof padString !== 'undefined' ? padString: ''));
        if (this.length > targetLength) {
            return String(this);
        }
        else {
            targetLength = targetLength-this.length;
            if (targetLength > padString.length) {
                padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
            }
            return String(this) + padString.slice(0,targetLength);
        }
    };
}

小结

今天你收获了吗?