javascript字符串统一采用utf-16编码,bmp字符占1个码元,辅助平面字符以代理对形式占2个码元,.length等方法按码元计数,需用array.from()或for-of遍历获取真实字符数。

UTF-16 编码结构:BMP 与代理对
Unicode 字符被划分为基本多文种平面(BMP,U+0000–U+FFFF)和辅助平面(U+10000–U+10FFFF)。BMP 中的字符在 JavaScript 中直接用一个 16 位码元表示,比如 'A' 对应 0x0041,'中' 对应 0x4E2D。
超出 BMP 的字符(如 ?❄️、?、?)无法用单个 16 位表示,必须拆成两个:一个高位代理(U+D800–U+DBFF)加一个低位代理(U+DC00–U+DFFF),合称代理对(surrogate pair)。例如:
• '?' 的 Unicode 码点是 U+20BB7,UTF-16 编码为 0xD842 0xDFB7
• '?'(U+1F600)编码为 0xD83D 0xDE00
JavaScript 的 .length、.charAt()、.charCodeAt() 等方法都按 16 位码元计数,因此它们对代理对会返回 2,而非逻辑上的 1。
正确获取字符数量和遍历字符串
想得到真实“字符个数”,不能依赖 str.length:
• 使用 Array.from(str).length 或 [...str].length
• 或调用 str.codePointAt(0) !== undefined 配合循环统计
安全遍历每个完整字符,推荐:
• for (const ch of str) —— 自动识别代理对,每次迭代一个逻辑字符
• 避免 for (let i = 0; i + str.charAt(i),它可能把代理对拆开,输出乱码或无效字符
正则与 Unicode 操作需显式启用 u 标志
默认正则(如 /./、/\w/)把代理对当作两个独立字符处理:
• /^.$/.test('?') 返回 false
• '?'.split('') 得到 ['\uD83D', '\uDE00']
加上 u 标志即可修复:
• /^.$/u.test('?') → true
• '?'.match(/./gu) → ['?']
• 'A?B'.split(/./u) 可正确切分(注意空字符串项)
所有 Unicode 相关操作,包括 .replace()、.search(),只要涉及辅助平面字符,都建议带上 u
码点与字符串的双向转换
ES6 提供了精准的码点级 API,绕过 UTF-16 代理细节:
• String.fromCodePoint(0x1F600) → '?'
• '?'.codePointAt(0) → 128512(即 0x1F600)
• String.fromCodePoint(0x20BB7) → '?'
而传统方法有局限:
• String.fromCharCode(0x1F600) 错误,只支持 BMP 范围(≤0xFFFF)
• '?'.charCodeAt(0) 返回高位代理值 55357(0xD83D),不是真正码点
• '?'.charCodeAt(1) 返回低位代理 56832(0xDE00),单独无意义
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











