charAt()和charCodeAt方法以及Unicode
在 JavaScript 中,字符串内部是以 UTF-16 编码存储和处理的。
UTF-16 是一种可变长度的 Unicode 编码方式,它使用 16 位(2 字节)或 32 位(4 字节) 来表示 Unicode 字符
对于基本多语言平面(BMP)内的字符(U+0000 到 U+FFFF),可以直接用 一个 16 位单元(称为 code unit) 表示
例如:
'A'(U+0041) →0x0041'中'(U+4E2D) →0x4E2D
'A'.length; // 1
'中'.length; // 1
对于辅助平面(Supplementary Planes)中的字符(U+10000 到 U+10FFFF),无法用单个 16 位单元表示,因此 UTF-16 使用 代理对(surrogate pair):
- 一个高位代理(high surrogate):范围
0xD800–0xDBFF(BMP中的特殊码点) - 一个低位代理(low surrogate):范围
0xDC00–0xDFFF(BMP中的特殊码点)
举例:
码点:U+1F600(😀,笑脸 emoji)的 UTF-16 编码为:0xD83D 0xDE00
'😀'.length; // 2 (U+1F600)
'🚀'.length; // 2 (U+1F680)
所以,注意str[index] 或 str.charAt(index) 返回的是 UTF-16 码元,不一定是完整 Unicode 字符,它可能返回单独代理项(lone surrogate)。
同样,String 的 charCodeAt(index) 方法返回一个整数,表示给定索引处的 UTF-16 码元,其值介于 0 和 65535 之间,此整数代表的码元,也不一定是完整 Unicode 字符。
如果要获取给定索引处的完整 Unicode 码位,请使用 String.prototype.codePointAt() 方法。
<script type="text/javascript">
let str="Hello world!";
console.log(str.charAt(4)); //输出字符 o
console.log(str.charCodeAt(4));//输出111(10进制)
let s = '😀';
console.log(s[0]); // (高位代理,单独无意义)
console.log(s[1]); // (低位代理,单独无意义)
</script>
正确处理完整 Unicode 字符的方法
- 使用 for...of(基于码点迭代):
for (let char of '😀') { console.log(char); // '😀' } - 使用
Array.from(str):Array.from('😀').length; // 1 - 使用
String.fromCodePoint()和codePointAt():'😀'.codePointAt(0); // 128512 (0x1F600) String.fromCodePoint(0x1F600); // '😀'
总结:
✅ JavaScript 字符串在内部使用 UTF-16 编码。
⚠️ 对于超出 BMP 的字符(U+10000 及以上),它们由两个 16 位单元(代理对)表示,因此:
.length可能不等于“视觉字符数”- 逐索引访问可能得到无意义的代理项
在处理国际化文本、emoji 或用户输入时,应优先使用 码点(code point) 相关 API(如 codePointAt, fromCodePoint, for...of)来避免错误。
浙公网安备 33010602011771号