每天学点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
修饰符号隐含了头部匹配的标志^
。