浅析ES6里关于字符串的拓展:子串识别、repeat、字符串补全、Unicode表示法、遍历器接口、JSON.stringify()的改造

一、子串识别

  自从 JS 引入了 indexOf() 方法,开发者们就使用它来识别字符串是否存在于其它字符串中。ES6 包含了以下三个方法来满足这类需求:

1、includes():该方法在给定文本存在于字符串中的任意位置时会返回 true ,否则返回false

2、startsWith():该方法在给定文本出现在字符串起始处时返回 true ,否则返回 false

3、endsWith():该方法在给定文本出现在字符串结尾处时返回 true ,否则返回 false 

  以上每个方法都接受两个参数:需要搜索的文本,以及可选的搜索起始位置索引

  (1)当提供了第二个参数(假设为n)时, includes() 与 startsWith() 方法会从该索引位置(n)开始尝试匹配;而endsWith() 方法则从字符串长度减去这个索引值的位置开始尝试匹配

  (2)当第二个参数未提供时, includes() 与 startsWith() 方法会从字符串起始处开始查找,而 endsWith() 方法则从尾部开始。实际上,第二个参数减少了搜索字符串的次数

  虽然这三个方法使得判断子字符串是否存在变得更容易,但它们只返回了一个布尔值(做判断的时候比较好用)。若需要找到它们在字符串中的确切位置,则需要使用indexOf() 和 lastIndexOf() 

  注意:如果向 startsWith() 、 endsWith() 或 includes() 方法传入了正则表达式而不是字符串,会抛出错误。而对于indexOf()和lastIndexOf()这两个方法,它们会将正则表达式转换为字符串并搜索它。

二、字符串重复

  ES6为字符串添加了一个 repeat() 方法,它接受一个参数作为字符串的重复次数,返回一个将初始字符串重复指定次数的新字符串

"abc".repeat(4)   // "abcabcabcabc"

  参数如果是小数,会被取整;如果repeat的参数是负数或者Infinity,会报错。

//如果参数是0到-1之间的小数,则等同于0,这是因为会先进行取整运算。0到-1之间的小数,取整以后等于-0,repeat视同为0
console.log('na'.repeat(-0.9)); // ""

//参数NaN等同于0
console.log('na'.repeat(NaN)); // ""

//如果repeat的参数是字符串,则会先转换成数字
console.log('na'.repeat('na')); // ""
console.log('na'.repeat('3'));  // "nanana"

  创建缩进级别:此方法比相同目的的其余方法更加方便,在操纵文本时特别有用,尤其是在需要产生缩进的代码格式化工具中

// 缩进指定数量的空格
var indent = " ".repeat(4),
indentLevel = 0;

// 需要增加缩进时
var newIndent = indent.repeat(++indentLevel);

//调用第一个repeat()方法创建了一个包含四个空格的字符串,indentLevel变量用来持续追踪缩进的级别。此后,可以通过增加indentLevel的值来调用repeat() 方法,从而改变空格数量

三、字符串补全

  ES6 引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全

1、padStart():头部补全

2、padEnd():尾部补全

  padStart()padEnd()一共接受两个参数,第一个参数用来指定字符串的最小长度,第二个参数是用来补全的字符串

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'

'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
//如果省略第二个参数,默认使用空格补全长度
'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x   '

//如果原字符串的长度,等于或大于指定的最小长度,则返回原字符串
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'

//如果用来补全的字符串与原字符串,两者的长度之和超过了指定的最小长度,则会截去超出位数的补全字符串
'abc'.padStart(10, '0123456789')// '0123456abc'

  应用:

//padStart的常见用途是为数值补全指定位数。下面代码生成10位的数值字符串
'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"

//另一个用途是提示字符串格式
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"

四、字符的 Unicode 表示法

  ES6 加强了对 Unicode 的支持,允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点。

"\u0061"  // "a"

  但是,这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。

"\uD842\uDFB7"    // '𠮷'
"\u20BB7"         // '₻7'

  上面代码表示,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JS会理解成\u20BB+7。由于\u20BB是一个不可打印字符,所以只会显示一个空格,后面跟着一个7

  ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。

"\u{20BB7}"    // "𠮷"
"\u{41}\u{42}\u{43}"    // "ABC"
let hello = 123;
hell\u{6F}   // 123
'\u{1F680}' === '\uD83D\uDE80'   // true

  上面代码中,最后一个例子表明,大括号表示法与四字节的 UTF-16 编码是等价的。有了这种表示法之后,JS 共有 6 种方法可以表示一个字符。

'\z' === 'z'  // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true

五、字符串的遍历器接口

  ES6为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历。

  除了遍历字符串,这个遍历器最大的优点是可以识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。

let text = String.fromCodePoint(0x20BB7);
for (let i = 0; i < text.length; i++) {
  console.log(text[i]);
}
// " "
// " "
for (let i of text) {
  console.log(i);
} // "𠮷"

  上面代码中,字符串text只有一个字符,但是for循环会认为它包含两个字符(都不可打印),而for...of循环会正确识别出这一个字符。

六、JSON.stringify() 的改造

  根据标准,JSON 数据必须是 UTF-8 编码。但是,现在的JSON.stringify()方法有可能返回不符合 UTF-8 标准的字符串。

  具体来说,UTF-8 标准规定,0xD800到0xDFFF之间的码点,不能单独使用,必须配对使用。比如,\uD834\uDF06是两个码点,但是必须放在一起配对使用,代表字符𝌆。这是为了表示码点大于0xFFFF的字符的一种变通方法。单独使用\uD834和\uDFO6这两个码点是不合法的,或者颠倒顺序也不行,因为\uDF06\uD834并没有对应的字符。

  JSON.stringify()的问题在于,它可能返回0xD800到0xDFFF之间的单个码点。

  为了确保返回的是合法的 UTF-8 字符,ES2019 改变了JSON.stringify()的行为。如果遇到0xD8000xDFFF之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。

JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""

 

posted @ 2017-11-20 23:03  古兰精  阅读(326)  评论(0编辑  收藏  举报