ES6 字符串扩展

1. 对双字节字符处理的弥补

之前Javascript允许通过\uxxxx的形式来表示一个字符,但是只限于0x0000-0xFFFF,对于双字节的字符,只能通过这样的方式表示\uD842\uDFB7,不过现在ES6可以通过将花括号包裹码点的方式,表示双字节字符,上述码点可以不用Unicode的UTF-16编码(Javascript内部用UTF-16进行编码),直接用Unicode编码表示\u{20BB7}

还有length()charAt(),charCodeAt()这些方法面对双字节字符时的表现如下:

var s = '\u{1F600}'; 
console.log("length: "+s.length);
console.log("0: " + s.charAt(0));
console.log("1: " + s.charAt(1));
console.log("char code 0: " + s.charCodeAt(0));
console.log("char code 1: " + s.charCodeAt(1)); 

结果如下:

length: 2
0:1: �
char code 0: 55357
char code 1: 56832 

很显然,这些方法把一个字符当做两个字符来处理了

  • codePointAt()

ES6提供了一个可以识别双字节字符的方法codePointAt,表现如下:

var s = '\u{1F600}'; 
console.log("char code 0: " + s.charCodeAt(0));
console.log("char code 1: " + s.charCodeAt(1));
console.log("Actual Char Code: " + s.codePointAt(0));
console.log("Actual Char: " + String.fromCodePoint(s.codePointAt(0)));
console.log("codePointAt1: " + s.codePointAt(1)); 

结果为:

char code 0: 55357
char code 1: 56832
Actual Char Code: 128512
Actual Char: 😀
codePointAt1: 56832 

我们可以看出codePointAt可以得出双字节字符对应的十进制数,其中String.fromCodePoint()是可以基于Unicode编码得到字符,我们得到一个emoji符号,不过codePointAt的第二个值还是原来charCodeAt()所得值,那么如何如何解决这个问题呢?看下面的代码:

var s = "a\u{20BB7}bc\u{1F600}";
for(var i=0, j=1; ;) {
 let t = s.codePointAt(i);
 if(t) {
   if (t>0xFFFF) {
     i = i+2;
   } else { 
     i++;
   }
   console.log(j + ":" + String.fromCodePoint(t));
   j++;
 } else {
   break;
 }
} 
1:a
2:𠮷
3:b
4:c
5:😀 

这样我们准确得到了我们的字符

  • for of

另外ES6还新增了字符串遍历接口,最大的特点就是能识别双字节字符

var s = "a\u{20BB7}bc\u{1F600}";
for(let i=0, j=1; ;) {
 let t = s.codePointAt(i);
 if(t) {
   if (t>0xFFFF) {
     i = i+2;
   } else { 
     i++;
   }
   console.log(j + ":" + String.fromCodePoint(t));
   j++;
 } else {
   break;
 }
}

let i = 1;
for(let a of s) {
 console.log(i + ":" + a);
 i++;
} 

结果如下:

1:a
2:𠮷
3:b
4:c
5:😀
----------------------
1:a
2:𠮷
3:b
4:c
5:😀 

和我们上述实现的迭代是一样的

  • at()

而至于无法识别双字节的charAt()方法,现在其实有个at()提案,可以识别双字节,目前的node平台是不支持这个方法的

console.log(String.prototype.at); // undefined 

不过有个垫片库实现了这个方法

->at()方法垫片库

2. 合成西欧字符 normalized()

var a = '\u01D1';
var b = '\u004F\u030C';
console.log(a);
console.log(b);
console.log(a==b.normalize()); 
Ǒ
Oˇ
true 

3. 字符搜索方法

var s = "hello world";
console.log("---------startsWith----------");
console.log(s.startsWith('hello')); //Does string s start with the param 'hello'?
console.log(s.startsWith('world'));
console.log(s.startsWith('r', 8)); // From the index of 8, the start of the string is 'r'?


console.log("---------endsWith----------");
console.log(s.endsWith('ld')); // Does string s end with the param 'ld'?
console.log(s.endsWith('hello'));
console.log(s.endsWith('w', 7)); // For the 7 chars in front of the string s, the ends of these is 'w'



console.log("---------includes----------");
console.log(s.includes('o')); // Does string s include the param 'o'?
console.log(s.includes('o', 6));


console.log("---------indexOf----------");
console.log(s.indexOf('ld')); // Get the index of the string 'ld' start position
console.log(s.indexOf('or', 6));
console.log(s.lastIndexOf('l')); // the last position of the char 'l' 

结果如下

---------startsWith----------
true
false
true
---------endsWith----------
true
false
true
---------includes----------
true
true
---------indexOf----------
9
7
9 

4. 字符串重复方法 repeat()

repeat()方法返回了一个新的字符串,重复了原字符串n次(n>=0

console.log("hello".repeat(2)); // "hellohello"
console.log("hello".repeat(0)); // "" 

5. 字符串补全方法

// 字符串补全padStart和padEnd可以接受两个参数
// 第一个参数是补全后的字符串大小
// 第二个参数是用于补全的字符串
// 补全规则遵循“多则重复,少则截取”的原则
// padStart将补全字符添加到字符串头
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'

// padEnd将补全字符添加到字符串尾
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba' 
// 如果第一个参数所规定的补全后的字符大小小于原有字符串大小,那么原样输出
'xxx'.padStart(2, 'ab') // 'xxx' 
// 如果第二参数省略,默认补全空格符
'x'.padStart(4) // '   x' 
// 常见用途是数值补全

'12'.padStart(10, '0') // "0000000012"
// 日期格式提示
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12" 

5. 模板字符串