codePointAt()与charCodeAt()方法区别
charCodeAt与codePointAt的用法:
- 相同点:
charCodeAt与codePointAt都是字符串实例上的方法,用途都是用来返回指定索引位字符的Unicode编码。 - 不同点:
charCodeAt与codePointAt匹配索引位的规则不一样。charCodeAt是根据码元来匹配,codePointAt是根据码点来进行匹配的。
JavaScript 内部,字符以 UTF-16(字符用两个字节或四个字节表示) 的格式储存,码点范围介于U+0000到U+FFFF,每个字符固定为2
个字节,一个码元。对于那些需要4
个字节储存的字符(Unicode 码点大于0xFFFF
的字符),两个码元,JavaScript 会认为它们是两个字符。
在计算机发展的早期,由于存储空间宝贵,Unicode使用16位二进制来存储文字。也就是一个码元来存储一个文字。
由于技术的发展,Unicode对文字编码进行了扩展,将某些文字扩展到了32位(占用两个码元),而一个文字对应的二进制数字是一个码点,所以使用32位二进制数字存储的文字(一个码点=两个码元)
特别要注意,码点可以是一个码元,也可以是两个码元。
字符串的length属性返回的是码元。所以在对一些字符串如果要处理长度的时候要注意这一点。
let str="A";
let strSpecial = "𠮷";
console.log(str.length); // 1
console.log(strSpecial.length); // 2
(1)length属性返回对应几个码元字符
(2)str的Unicode是\u0041\只有一个字符,strSpecial Unicode编码是\ud842\udfb7,双字节两个码元,js识别为2个字符
let str="A";
let strSpecial = "𠮷";
console.log(str.charCodeAt(0)); // 65
console.log(str.codePointAt(0)); // 65
console.log(strSpecial.charCodeAt(0)); // 55362
console.log(strSpecial.codePointAt(0)); // 134071
ES6 提供了codePointAt(0)方法,能够正确处理 4 个字节储存的字符,根据字符串码元的位置得到其码点。
- 𠮷这个字的Unicode编码是\ud842\udfb7,占用了两个码元。
- 所以当用charCodeAt(0)是匹配0位的码元,前两个字节值 55362,toString(16)是ud842。
- 当用codePointAt(0)是匹配0位的码点,codePointAt能识别出字符串的码点,所以反回134071。
codePointAt方法返回的是码点的十进制值,如果想要十六进制的值,可以使用toString方法转换一下。
let a = 'A';
let s = '𠮷';
a.codePointAt(0).toString(16)
"41"
s.codePointAt(0).toString(16)
"20bb7"
但是这里需要注意参数:
let strSpecial = "𠮷";
console.log(strSpecial.charCodeAt(1));
console.log(strSpecial.codePointAt(0));
console.log(strSpecial.codePointAt(1));
image.png
codePointAt(1)与charCodeAt(1)的返回值相同,都是返回后两个字节的码元值。
这是因为索引位是根据码元,而匹配的规则是根据码点的规则。如果后面两位码元是一个码点,就会当作一个码点来处理。
let str="A";
let strSpecial = "𠮷A";
console.log(str.charCodeAt(0));
console.log(strSpecial.codePointAt(0));
console.log(strSpecial.codePointAt(1));
console.log(strSpecial.codePointAt(2));
image.png
strSpecial.codePointAt(1)取的不是A的字符值,是strSpecial后两个字节的码元值,而.codePointAt(2)才取得A的字符值,与str.charCodeAt(0)一样。
解决顺序问题的配套办法是使用for...of循环,因为它可以识别UTF-32(字符用四个字节表示,两个码元)
let strSpecial = "𠮷";
for (let char of strSpecial) {
console.log(char.codePointAt(0));
}
关于for of可以参阅JavaScript for of 循环一章节。
codePointAt()方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。
function is32Bit(c) {
// 如果码点大于了16位二进制的最大值,则其是32位的
return c.codePointAt(0) > 0xFFFF;
}
is32Bit("𠮷") // true
is32Bit("a") // false
有用的字符编码笔记:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
欢迎大佬指点