charcodeat() 返回 utf-16 编码单元而非 unicode 码点,处理 emoji 等超出 bmp 的字符时需用代理对计算;推荐使用 codepointat() 获取正确码点,且需注意字符串 length 与实际字符数的差异。

JavaScript 的 charCodeAt() 返回的是 UTF-16 编码单元(code unit),不是 Unicode 码点(code point)。这对处理中文、emoji、数学符号等超出基本多文种平面(BMP)的字符时,容易出错。
charCodeAt 返回的是 UTF-16 编码单元,不是 Unicode 码点
UTF-16 用 16 位(2 字节)表示大部分常用字符(U+0000–U+FFFF),这部分叫 BMP;但超出 BMP 的字符(如 ? U+1F30D、?? U+1F469 U+200D U+1F4BB)需用两个 16 位单元表示——即“代理对”(surrogate pair)。此时 charCodeAt() 对一个 emoji 会返回两个不同值,每个只对应一个代理单元,而非完整码点。
-
'A'.charCodeAt(0)→ 65(正确,单个 BMP 字符) -
'?'.charCodeAt(0)→ 55357(高位代理,0xD83D),'?'.charCodeAt(1)→ 56836(低位代理,0xDE04) - 直接拼这两个数得不到 U+1F604,需按 UTF-16 代理对规则计算:
(high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000
推荐用 codePointAt 替代 charCodeAt 处理完整字符
String.prototype.codePointAt() 是 ES2015 引入的,能正确返回任意字符(包括代理对)对应的 Unicode 码点,单位是整数,且与 Unicode 标准一致。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
'?'.codePointAt(0)→ 128516(即 0x1F604) -
'??'.codePointAt(0)→ 128105(U+1F469),注意这个组合字符实际由多个码点 + ZWJ 构成,codePointAt只取首码点;若需完整解析,需配合Array.from(str)或正则/\p{Extended_Pictographic}/u - 对 BMP 字符,
codePointAt(i)和charCodeAt(i)结果相同
遍历字符串时小心 length 和索引偏移
字符串的 .length 返回 UTF-16 编码单元个数,不是字符个数。一个 emoji 可能占 2 个长度单位,导致 for (let i = 0; i 循环中,<code>i 跳过代理对的第二部分,或在 i+1 处读到无效代理单元。
- 错误示例:
for (let i = 0; i → 对 ? 输出两个孤立代理值 - 安全做法:用
for (const ch of s)(支持代理对)、Array.from(s)(生成真正字符数组)、或s.codePoints()(ES2024 提案,暂未广泛支持) - 若必须用索引遍历,检查是否为代理对开头:
if (s.charCodeAt(i) >= 0xD800 && s.charCodeAt(i) ,再读取下一位合并
兼容性与实际建议
codePointAt 在现代浏览器和 Node.js(≥ v4)中已全面支持;for...of 和 Array.from 也早已可用。除非要支持 IE11 或极老环境,否则无需手动处理代理对。
- 新代码一律优先用
codePointAt()替代charCodeAt() - 需要逐字符操作时,用
Array.from(str)而非str.split('')(后者不拆分代理对) - 做字符比较、截断、计数等逻辑前,先确认字符串是否含 emoji/生僻汉字/数学符号,避免因长度误判引发 bug
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










