1、字符串的Unicode 表示法
javascript 允许采用 \uxxxx 表示一个字符,其中 xxxx 表示字符的码点。
"\u0061" // "a"
ES5中的缺陷:
以上表示法只限于 \u0000——\uFFFF 之间的字符。超出这个范围的=字符,必须用两个双字节表示。
"\uD842\uDFB7" //"??"
如果直接在\u 后面直接加上超过\uFFFF 的数值:
"\u20BB7" // " 7"
如上代码,JavaScript会理解成 “\u20BB+7” 。由于\u20BB 是一个不可打印字符, 所以显示一个空格。
ES6的改进:
只要将码点放入大括号,就能正确解读改字符。
"\u{20BB7}" // "??" "\u{41}\u{42}\u{43}" // "ABC" let hello = 123; hell\u{6F} // 123
‘\u{1F680}‘ === ‘\uD83D\uDE80‘ // true 此行代码表示:大括号表示法 与 四字节的UTF-16编码是等价的。
在JavaScript 中共有6种方法可以表示一个字符:
‘\z‘ === ‘z‘ // true ‘\172‘ === ‘z‘ // true ‘\x7A‘ === ‘z‘ // true ‘\u007A‘ === ‘z‘ // true ‘\u{7A}‘ === ‘z‘ // true
2、codePointAt()
JavaScript 内部,字符以UTF-16 的格式存储,每个字符固定为2字节。 对于Unicode 码点大于0xFFFF 的字符(需要4个字节存储),js会认为它们是2 个字符。
ES5的缺陷:
var s = "??"; s.length // 2 s.charCodeAt(0) // 55362 s.charCodeAt(1) // 57271
上面的代码中,?? 的码点是0x20BB7,UTF-16 编码为0xD842 0xDFB7
(十进制为55362 57271
),需要4
个字节储存。
对于这种四字节字符,JavaScript不能正确处理,字符串长度会被误认为2;charCodeAt 方法只能分别返回前两个字节的值 和 后两个字节的值。
ES6 的改进:
提供了codePointAt方法,能够正确处理4 字节字符,返回一个32位的UTF-16字符的码点。(返回的码点是十进制的)
let s = ‘??a‘; s.codePointAt(0) // 134071 s.codePointAt(1) // 57271 s.codePointAt(2) // 97
参数为字符在字符串中的位置(从0开始); 对于两个字节存储的常规字符,它的返回结果与charCodeAt方法相同。
若要codePointAt方法返回的是十六进制的值,可以使用 toString方法转换一下。
let s = ‘??a‘; s.codePointAt(0).toString(16) // "20bb7" s.codePointAt(2).toString(16) // "61"
以上代码仍然存在问题:codePointAt方法的参数仍然是不正确的。【a在字符串的位置是1, 但是传参却是2】
解决方法: 使用for…of 循环,因为它可以正确识别32位的 UTF-16字符。
let s = ‘??a‘; for (let i of s) { console.log( i.codePointAt(0).toString(16) ); } // "20bb7" // "61"
codePointAt 方法 是测试一个字符由 2个字节 还是 4个字节 组成的最简单的方法。
function is32Bit( c ) { return c.codePiontAt(0) > 0xFFFF; }
is32Bit("??"); // true
is32Bit("a"); // true
3、String.fromCodePoint()
ES5 的缺陷:
String.fromCharCode 用于从码点返回对应的字符,但是不能识别大于Unicode编码 0xFFFF 的字符(32位的UTF-16字符)
String.fromCharCode(0x20BB7) // "?"
上面代码 0x20BB7发生溢出最高位两位被舍弃,最后返回码点U+0BB7
对应的字符,而不是码点U+20BB7
对应的字符。
ES6的改进:
String.fromCodePoint 方法,可以识别大于0xFFFF 的码点;作用上正好与 codePointAt 相反。
String.fromCodePoint(0x20BB7) // "??" String.fromCodePoint(0x78, 0x1f680, 0x79) === ‘x\uD83D\uDE80y‘ // true
方法中有多个参数,则它们会被合并成一个字符串返回。
注意: fromCodePoint 方法定义在 String对象上, 而codePointAt 方法定义在字符串的实例对象上。