JS字符串编码问题

在ES5之前,JS的字符串以16位的字符编码为基础。每个16位的序列都是一个码元,表示一个字符。但随着Unicode引入了扩展字符集,16位的字符编码便不再够用了(UTF-16 是变长的字符编码方式,有 16 位与 32 位两种情况。 JS 原先使用的则是固定 16 位(双字节)的字符编码方式)

UTF-16 码点

在UTF-16中位于0x0000-0xFFFF之间的码点,直接使用相同的16位码元表示,这个范围被称为多语言基本平面(BMP),超出该范围的码点将会落到扩展平面上。UTF-16引入代理对(使用两个16位的码元来表示单个码点)来解决这个问题 ;。

在ES5中,所有的字符串操作都是基于16位的码元,这表明在处理包含代理对UTF-16字符会出现意料外的结果。

vat text = "?"
console.log(text.length); // 2
console.log(/^.$/.test(text)); // false
console.log(text.charAt(0)); // ""
console.log(text.charAt(1)); // ""
console.log(text.charCodeAt(0)); // 55362
console.log(text.charCodeAt(1)); // 57271

这里"?"使用两个16位的码元表示,,所以在正则匹配单个字符的时候会返回false,charAt无法返回一个有效的字符,因为这里每16位码点都不是一个可打印的字符。
charCodeAt() 方法同样无法正确识别该字符,它只能返回每个码元的 16 位数字,但在 ES5中,这已经是对 text 变量所能获取到的最精确的值了。

codePointAt() 方法

ES6 为全面支持 UTF-16 而新增的方法之一是 codePointAt() ,它可以在给定字符串中按位置提取 Unicode 码点。该方法接受的是码元位置而非字符位置,并返回一个整数值,就像
下面的 console.log() 范例所展示的:

var text = "?a" ;
console.log(text.charCodeAt(0)); // 55362
console.log(text.charCodeAt(1)); // 57271
console.log(text.charCodeAt(2)); // 97
console.log(text.codePointAt(0)); // 134071
console.log(text.codePointAt(1)); // 57271
console.log(text.codePointAt(2)); // 97

codePointAt() 方法的返回值一般与 charCodeAt() 相同,除非操作对象并不是 BMP 字符。
text 字符串的第一个字符不是 BMP 字符,因此它占用了两个码元,意味着该字符串的length 属性是 3 而不是 2 。 charCodeAt() 方法只返回了位置 0 的第一个码元;而codePointAt() 返回的是完整的码点,即使它占用了多个码元。对于位置 1 (第一个字符的第二个码元)和位置 2 ( “a” 字符)来说,两个方法返回的值则是相同的。

你可能感兴趣的:(javascript,javascript,码元,码点,utf-16)