JavaScript字符串需用codePointAt()、fromCodePoint()和for...of处理Unicode字符,因UTF-16编码下大于0xFFFF的码点(如emoji、古文字)会形成代理对,传统方法易出错;codePointAt()正确返回完整码点,fromCodePoint()可构造任意字符,for...of按码点遍历,避免截断。

JavaScript 中字符串默认按 UTF-16 编码处理,遇到 Unicode 码点大于 0xFFFF 的字符(如部分 emoji、古文字、数学符号等),单靠 .charCodeAt() 或 for...of 循环可能出错或截断。CodePoint 是真正的 Unicode 字符编号(范围 U+0000 到 U+10FFFF),用它才能准确识别、遍历和操作所有合法字符。
用 codePointAt() 获取字符的真实码点
String.prototype.codePointAt(index) 返回指定位置字符的完整 Unicode 码点(十进制数),能正确处理代理对(surrogate pairs)。
- 普通 ASCII 字符(如
'A')返回65,和charCodeAt()一致 - emoji 如
'??'(程序员 emoji,由多个码点组合)或'?'(U+20BB7)会返回完整码点值,比如'?'.codePointAt(0)返回134071 - 若位置落在代理对的后半部分(如
'?'.charCodeAt(1)),codePointAt(1)会返回undefined,安全但需注意索引
用 String.fromCodePoint() 构造任意字符
String.fromCodePoint(...codePoints) 是 String.fromCharCode() 的升级版,支持传入任意合法码点(包括 > 0xFFFF 的值)。
-
String.fromCodePoint(0x1F468, 0x200D, 0x1F4BB)→'??'(组合型 emoji) -
String.fromCodePoint(0x20BB7)→'?',而String.fromCharCode(0x20BB7)会错误地生成两个乱码字符 - 可一次传入多个码点,直接拼成字符串:
String.fromCodePoint(0x4F60, 0x597D)→'你好'
用 for...of 正确遍历所有字符(隐式使用 CodePoint)
for...of 遍历字符串时,底层按 Unicode 码点而非 UTF-16 单元工作,天然支持代理对。
立即学习“Java免费学习笔记(深入)”;
-
for (const ch of '?a') { console.log(ch); }输出'?'和'a'(2 次迭代) - 对比
for (let i = 0; i :长度为 3(因为 <code>'?'占 2 个 UTF-16 单元),循环会取到无效中间单元 - 扩展运算符
[...'?a']同样按码点分割,结果是['?', 'a']
检测和过滤非 BMP 字符(可选增强逻辑)
若需区分基本多文种平面(BMP,U+0000–U+FFFF)与补充字符,可用 codePointAt() 判断:
function isSupplementary(cp) { return cp > 0xFFFF; }-
'?'.codePointAt(0) > 0xFFFF→true - 过滤掉所有 emoji:
'Hello ??!'.split('').filter(ch => ch.codePointAt(0) → <code>'Hello !'(注意:有些 emoji 是组合序列,此法仅过滤单个码点 emoji)
不复杂但容易忽略:只要涉及 emoji、罕见汉字、数学符号或国际化文本,就该优先用 codePointAt、fromCodePoint 和 for...of,而不是老式 UTF-16 方法。


















