每天学点ES6-字符串
ES6中对字符串进行了很多扩展,包括加强了Unicode的支持、
更好的Unicode支持
在ES6之前,JavaScript的字符串是完全基于16位字符编码的想法。所有字符串的属性和方法,例如:length和charAt(),都是基于16位序列代表单个字符的想法。ES5还允许Javascript引擎决定使用哪种编码方式,UCS-2或UTF-16。
对于Unicode的既定目标,保持在16位是不可能的为全世界的每一个字符提供一个全局唯一的标识符。这些全局唯一标志服被称之为code point,且从0开始。一个字符串编码有责任编码一个code point为code unit,且保持内部一致。
第一个2^16个code point在UTF-16中被表示为单一的16位code unit。这被称之为Basic Multilingual Plane (BMP)。超出该范围的被认为是在一个辅助平面,code point已不能仅仅用16位来表示了。UTF-16通过引入surrogate pairs(代理对)来解决这个问题,一个code point可以由两个16位的code unit来表示。这意味着字符串中的任何单个字符可以由一个code unit或两个来表示。
在ES5中所有的操作都是基于16位的code unit,这意味着你在处理包含代理对的字符串时会出现意想不到的结果。例如:
1 | var text = "𠮷"; |
在这个例子中,单个Unicode字符是使用代理对来表示的,JavaScript字符操作会认为字符串由两个16位的字符组成。这意味着length为2,通过正则表达式匹配单个字符也失败了,charAt()也无法读取字符。charCodeAt()方法为每个code unit返回了正确的16为数字。
在ES6中强制使用UTF-16来编码字符串。
codePointAt()
codePointAt()接受code unit的位置,并返回一个整数:
1 | var text = "𠮷a"; |
当字符为BMP范围内的字符时,codePointAt()和charCodeAt()的行为是一样的,在非BMP字符时,charCodeAt()仅仅返回了位置0的code unit,但是codePointAt()返回了整个code point,即使横跨多个code unit。对于位置1和位置2的,它俩返回值是相同的。
用以下方法可以判断是否为16位,还是32位:
1 | function is32Bit(c) { |
String.fromCodePoint()
String.fromCodePoint()就是和codePointAt()做相反的操作了。例如:
1 | console.log(String.fromCodePoint(134071)); // "𠮷" |
编码非BMP字符
在ES5中允许字符包含用编码序列代表的16位Unicode字符。编码序列是通过\u加上4个16进制值,例如\u0061代表字符a:
1 | console.log("\u0061"); // "a" |
但是当你用编码序列来代表大于FFFF的字符时,你会得到意想不到的结果:
1 | console.log("\u20BB7"); |
因为Unicode编码序列总是包含4个16进制字符,ECMAScript计算\u20BB7为两个字符:\u20BB和7。第一个字符为非打印的,第二个为数字7。
ES6通过引入扩展的Unicode编码序列解决了这个问题,将16进制数字包含在花括号内。这使得任何数量的十六进制字符可以指定为单个字符:
1 | console.log("\u{20BB7}"); // "𠮷" |
通过下面的函数可以判断是否支持这种写法:
1 | function supportsExtendedEscape() { |
正则表达式u修饰符
正则表达式也是基于16位的code unit来代表单个字符,这就对于𠮷在/^.$/的正则表达式中不能匹配,ES6为正则表达式定义了一个新的修饰符,u也即Unicode。当一个正则表达式设置了u修饰符时,它将切换模式为工作在字符串,而不是code unit。这意味着正则表达式在包含代理对的字符串中不会迷惑。例如:
1 | var text = "𠮷"; |
在添加了u修饰符的正则表达式能以字符的方式来匹配字符串,而不是code unit。
新增的String方法
includes()
如果给定字符在字符串的任何位置被找到,则返回true,否则返回false。例如:
1 | var msg = "Hello world!"; |
startsWith()
如果字符串以给定字符开始,则返回true,否则返回false。例如:
1 | var msg = "Hello world!"; |
endsWith()
如果字符串以给定字符结束,则返回true,否则返回false。例如:
1 | var msg = "Hello world!"; |
repeat()
该方法接受一个数字作为参数,表示将原字符串重复的次数。例如:
1 | var str = "cookfront"; |
正则表达式修饰符y
ES6引入了新的正则表达式修饰符y,也即粘连,它与g修饰符比较类似,但是不同之处在于,g修饰符只确保剩余位置中存在匹配,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是粘连的涵义。例如:
1 | var text = "hello1 hello2 hello3", |
在上面的例子中,使用了三个正则表达式,一个使用了y修饰符,一个使用了g修饰符,一个没有使用修饰符。第一次匹配时我们可以看到结果都为hello1,匹配后我们将lastIndex置为1,即从第二个字符开始匹配,我们可以看到第二次匹配的结果没有修饰符的还是匹配hello1,g修饰符的匹配hello2,y修饰符在从第二个字符开始没有匹配任何东西所以返回null。我们也可以看出了y修饰符号隐含了头部匹配的标志^。

