深入理解ES6-第2章-字符串和正则表达式

2.字符串和正则表达式

2.1更好的Unicode支持

  在es6出现之前,javascript字符串一直都是基于16位字符编码(UTF-16)进行创建。每16位的序列是一个编码单元,代表一个字符。length、charAt()等字符串属性和方法都是基于这种编码单元构造的。

UTF-16码位

  Unicode的目标时为全世界每一个字符提供全球唯一的字符串(又被称作码位,是从0开始的数值,按顺序排列)。而表示字符的这些数值或码位,我们称之为字符编码(character encode)。字符编码必须将码位编码为内部统一的编码单元。
  对于UTF-16来说,前216个码位均已16位的编码单元表示,这个范围被称作基本多文种平面(BMP)。超出这个范围的码位则要归属于某个辅助平面,其中的码位仅用16位就无法表示了。为此,UTF-16引入了代理对,其规定用两个16位编码单元表示一个码位。也就是说,字符串里的字符有两种,一种是由一个编码单元16位表示的BMP字符,另一种是由两个编码单元32位表示的辅助平面字符。
  在ES5中,所有字符串的操作都基于16位编码单元。如果采用同样的方式处理包含代理对的UTF-16编码字符,得到的结果可能与预期不符。

codePointAt()方法

  方法接受编码单元的位置而非字符串位置作为参数。
  对于非BMP字符集来说,它占用两个编码单元,第一个编码单元codePointAt()返回完整的码位,而第二个编码单元与BMP字符集中字符返回与charCodeAt()相同。
  当该方法返回的数字大于0xFFFF时,为非BMP字符集中字符。

String.fromCodePoint()方法

  参数为码位,根据它生成一个字符。看成完整版的String.fromCharCode()。

normalize()方法

  在对比字符串之前,一定先把它们标准化为同一种形式。

1
2
3
4
5
6
7
8
9
10
11
values.sort(function(first,second){
let firstNormalized = first.normalize();
let secondNormalized = second.normalize();
if (firstNormalized < secondNormalized) {
return -1;
} else if (firstNormalized === secondNormalized) {
return 0;
} else {
return 1;
}
});

正则表达式u修饰符

从编码单元操作模式切换为字符模式,可以视代理为一个字符。

  • 计算码位数量
    1
    2
    3
    4
    function codePointLength(text){
    let result = text.match(/[\s\S]/gu);
    return result ? result.length : 0;
    }

检测空格和非空格字符

  • 检测u修饰符支持
    1
    2
    3
    4
    5
    6
    7
    8
    function hasRegExpU(){
    try{
    var pattern = new RegExp(‘.’, ‘u’);
    return true;
    }catch (ex){
    return false;
    }
    }

2.2其他字符串变更

  字符串中的子串识别

  • includes()方法——如果字符串中检测到指定文本则返回true,否则返回false;
  • startsWith()方法——如果字符串的起始部分检测到指定文本则返回true,否则返回false;
  • endsWith()方法——字符串的结束部分检测到指定文本则返回true;
      以上方法都接收两个参数:第一个是要搜索的文本,第二个参数可选,为开始搜索位置的索引值。Includes()方法和startsWith()方法会从这个索引值的位置开始匹配,endsWith()则从字符串长度减去这个索引值的位置开始匹配,即从后往前数第多少位。参数不能传入正则表达式。
    repeat()方法
      接受一个number参数,表示字符串重复次数,返回值是当前字符串重复一定次数后的新字符串。

    2.3其他正则表达式语法变更

    正则表达式y修饰符
      它会影响正则表达式搜索过程中的sticky属性,当在字符串中开始字符匹配时,它会通知搜索从正则表达式的lastIndex属性开始进行,若该位置没能匹配成功,则停止继续匹配。
      只有调用exec()和test()这些正则表达式对象方法时才会涉及lastIndex属性;调用字符串方法不会触发粘滞行为。
      检测y修饰符是否存在,应该检测正则表达式的sticky属性。
      可用与u类似的方法来检测引擎支持程度。
    1
    2
    3
    4
    5
    6
    7
    8
    function hasRegExpY(){
    try{
    var pattern = new RegExp(‘.’, ‘y’);
    return true;
    }catch (ex){
    return false;
    }
    }
正则表达式的复制
1
2
var re1 = /ab/I,
re2 = new RegExp(re1);

  此时re2为re1的一份拷贝,若

1
var re2 = new RegExp(re1, 'g');

  在ES5中会抛出错误,而ES6中不会,且修改了re2的修饰符。

flags属性

  为只读的原型属性访问器,只定义了getter方法。返回所有应用于当前正则表达式的修饰符字符串。source属性可获取正则表达式的文本。

2.4模板字面量

  ES6模板字面量支持创建领域专用语言(DSL)。DSL为某些具体而有限的目标设计的语言。模板字面量草案:这个方案是扩展ECMAScript基础语法的语法糖,其提供一套生成、查询并操作来自其他语言里内容的DSL,且可以免受注入攻击,例如XSS,SQL注入等。
  ES6通过模板字面量的方式进行了填补:

  • 多行字符串——一个正式的多行字符串的概念。
  • 基本的字符串格式化——将变量的值嵌入字符串的能力。
  • HTML转义——向HTML插入经过安全转换后的字符串的能力。
    基础语法
      通过(`)引用。内部使用反撇号时需用\转义。
    多行字符串
    ES6之前版本中的解决方案
      在一个新行最前方添加反斜杠(\)可以承接上一行的代码。
    1
    2
    3
    var message = “Multiline \
    string”;
    console.log(message); //”Multiline string”

  如果想输出新的一行,需要手动输入换行符;

1
2
3
var message = “Multiline \n\
string”;
console.log(message); //”Multiline string”

  或者依靠数组和字符串拼接方法建多行字符串。

1
2
3
4
5
var message = [
"Muitiline",
"string"
].join("\n");
let message = “Multiline \n” + “string”;

简化多行字符串

  如果需要在字符串中添加新的一行,只需在代码中直接换行,此处的换行结果将同步出现在结果中。
  在反撇号中所有空白符都属于字符串的一部分,所以要千万小心缩进。
如果一定要通过适当的缩进来对齐文本,可以砸多行模板字面量中的第一行留白,后面几行缩进,并调用trim()方法移除最初的空格。

1
2
3
4
5
let html = `
<div>
<h1>Title</h1>
</div>
html.trim();

  也可以在模板字面量中显示使用\n来插入换行。

字符串占位符

  用${.}表示,内部嵌入JavaScript表达式并将其作为字符串的一部分输出到结果中。一个模板字面量可以嵌套另一个。

标签模板

  每个模板标签都可以执行模板字面量上的转换并返回最终的字符串值。标签指的是模板字面量第一个反撇号(`)前方标注的字符串。

1
let message = tag`Hello world`;

  改模板字面量标签为tag。

定义标签
在模板字面量中使用原始值

  使用内建的String.raw标签

1
2
let message = String.raw`Multiline\nstring`;
console.log(message); //”Multiline\\nstring”