ES6加强了对Unicode的支持,并且扩展了字符串对象。
一、字符的Unicode表示法
JavaScript允许采用\uxxxx形式表示一个字符,其中“xxxx”表示字符的码点。
{
let str = '\u0062'; //js采用十六进制编码格式存储值 范围是\u0000--\uFFFF
console.log(str) //b
}
但是,这种表示法只限于\u0000——\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表达。
let str = '\uD842\uDFB7'; //UTF-16编码
console.log(str); // "𠮷"
let str1 = "\u20BB7" //码点
console.log(str1); // " 7"
上面代码表示,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript会理解成\u20BB+7。由于\u20BB是一个不可打印字符,所以只会显示一个空格,后面跟着一个7
二、ES6改进(加花括号)
let str = '\u{20BB7}';
console.log(str); // "𠮷"
'\u{20BB7}'=='\uD842\uDFB7' //true
三、方法
JavaScript内部,字符以UTF-16的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode码点大于0xFFFF的字符),JavaScript会认为它们是两个字符,超出这个范围的字符,必须用两个双字节的形式表达。
- charAt()方法 (返回字符串给定位置的字符)
*********超出范围***********
{
let str = "𠮷";
console.log(str.length); //2
console.log(str.charAt(0)); //�
console.log(str.charAt(1)); //�
}
*********范围之内***********
{
let str = "吉";
console.log(str.length); //1
//length得到的是字符的长度,而不是字节的长度,一个汉字和一个英文的length都应该是1
console.log(str.charAt(0)); //吉
}
上面代码中,汉字“𠮷”(注意,这个字不是”吉祥“的”吉“)的码点是0x20BB7,UTF-16编码为0xD842 0xDFB7(十进制为55362 57271),需要4个字节储存。对于这种4个字节的字符,JavaScript不能正确处理,字符串长度会误判为2,而且charAt方法无法读取整个字符,如果用charCodeAt方法只能分别返回前两个字节和后两个字节的值。
- charCodeAt()方法(返回的是十进制值)
//charCodeAt方法
{
let str = "𠮷";
console.log(str.charCodeAt(0).toString(16)); //d842
console.log(str.charCodeAt(1).toString(16)); //dfb7
等同于:
//\uD842\uDFB7(UTF-16编码)
}
- codePointAt()方法(返回值是十进制)
ES6提供了codePointAt方法,能够正确处理4个字节储存的字符,返回一个字符的码点,codePointAt方法的参数,是字符在字符串中的位置(从0开始)。
{
let str = "𠮷a";
console.log(str.codePointAt(0).toString(16)) // "20bb7"
console.log(str.codePointAt(1).toString(16)) // "dfb7"
console.log(str.codePointAt(2).toString(16)) // "61"
}
你可能注意到了,codePointAt方法的参数,仍然是不正确的。比如,上面代码中,字符a在字符串str的正确位置序号应该是1,但是必须向codePointAt方法传入2。解决这个问题的一个办法是使用for...of循环,因为它会正确识别32位的UTF-16字符
{
let str = "𠮷a";
for(let s of str) {
console.log(s.codePointAt().toString(16)) // "20bb7" "61"
}
}
应用场景:判断当前字符是否大于0xFFFF
{
function fn(str){
return str.codePointAt(0) > 0xFFFF;
}
console.log(fn("你")) //false
console.log(fn("𠮷")) //true
}
- at()方法:
ES5对字符串对象提供charAt方法,返回字符串给定位置的字符。该方法不能识别码点大于0xFFFF的字符。
{
console.log('abc'.charAt(0)); // "a"
console.log('𠮷'.charAt(0)); // "�"
}
上面代码中,charAt方法返回的是UTF-16编码的第一个字节,实际上是无法显示的。
目前,有一个提案,提出字符串实例的at方法,可以识别Unicode编号大于0xFFFF的字符,返回正确的字符。
{
console.log('abc'.at(0)); // "a"
console.log('𠮷'.at(0)); // "𠮷"
}
这个方法可以通过垫片库pollfiy实现。
总结:
ES5
- charAt()返回指定位置的字符,前提是不大于0xFFFF的字符;如果大于0xFFFF的字符,返回一个不识别的字符。
- charCodeAt()返回指定位置的字符十进制码点;如果是一个大于0xFFFF的字符,则分别返回前两个字节和后两个字节的的十进制值。
ES6
- at()返回指定位置的字符,修正了charAt()不能解析大于0xFFFF的字符。
- codePointAt()使用for...of循环,能够正确处理4个字节储存的字符,返回一个字符的码点。






网友评论