JavaScript:charCodeAt()和codePointAt()的区别

JavaScript中的charCodeAt()返回Unicode编码,对于4字节字符处理不正确,而codePointAt()能正确处理,尤其在处理Unicode码点大于0xFFFF的字符时。codePointAt()返回码点的十进制值,使用for...of循环或扩展运算符可正确处理多字节字符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • charCodeAt()

    str.charCodeAt(index)
    

    返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。
    如果 index 是负数,或大于等于字符串的长度,则 charCodeAt() 返回 NaN。

    var str = "javascript";
    str.charCodeAt(2); // 118
    str.charCodeAt(12); // NaN
    str.charCodeAt(-2); // NaN
    
  • codePointAt()

    str.codePointAt(index)
    

    返回指定位置的字符的 Unicode 编码。
    如果 index 是负数,或大于等于字符串的长度,则 codePointAt() 返回 undefined。

    var str = "javascript";
    str.codePointAt(2); // 118
    str.charCodeAt(12); // undefined
    str.charCodeAt(-2); // undefined
    
  • 区别
    JavaScript 内部,字符以 UTF-16 的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符。

    var s = "𠮷";
    
    s.length // 2
    s.charAt(0) // ''
    s.charAt(1) // ''
    s.charCodeAt(0) // 55362
    s.charCodeAt(1) // 57271
    

    上面代码中,汉字“𠮷”(注意,这个字不是“吉祥”的“吉”)的码点是0x20BB7,UTF-16 编码为0xD842 0xDFB7(十进制为55362 57271),需要4个字节储存。对于这种4个字节的字符,JavaScript 不能正确处理,字符串长度会误判为2,而且charAt()方法无法读取整个字符,charCodeAt()方法只能分别返回前两个字节和后两个字节的值。

    ES6 提供了codePointAt()方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。

    let s = '𠮷a';
    
    s.codePointAt(0) // 134071
    s.codePointAt(1) // 57271
    
    s.codePointAt(2) // 97
    

    codePointAt()方法的参数,是字符在字符串中的位置(从 0 开始)。上面代码中,JavaScript 将“𠮷a”视为三个字符,codePointAt 方法在第一个字符上,正确地识别了“𠮷”,返回了它的十进制码点 134071(即十六进制的20BB7)。在第二个字符(即“𠮷”的后两个字节)和第三个字符“a”上,codePointAt()方法的结果与charCodeAt()方法相同。

    总之,codePointAt()方法会正确返回 32 位的 UTF-16 字符的码点。对于那些两个字节储存的常规字符,它的返回结果与charCodeAt()方法相同。

    codePointAt()方法返回的是码点的十进制值,如果想要十六进制的值,可以使用toString()方法转换一下。

    let s = '𠮷a';
    
    s.codePointAt(0).toString(16) // "20bb7"
    s.codePointAt(2).toString(16) // "61"
    

    你可能注意到了,codePointAt()方法的参数,仍然是不正确的。比如,上面代码中,字符a在字符串s的正确位置序号应该是 1,但是必须向codePointAt()方法传入 2。解决这个问题的一个办法是使用for…of循环,因为它会正确识别 32 位的 UTF-16 字符。

    let s = '𠮷a';
    for (let ch of s) {
      console.log(ch.codePointAt(0).toString(16));
    }
    // 20bb7
    // 61
    

    另一种方法也可以,使用扩展运算符(…)进行展开运算。

    let arr = [...'𠮷a']; // arr.length === 2
    arr.forEach(
      ch => console.log(ch.codePointAt(0).toString(16))
    );
    // 20bb7
    // 61
    

    codePointAt()方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。

    function is32Bit(c) {
      return c.codePointAt(0) > 0xFFFF;
    }
    
    is32Bit("𠮷") // true
    is32Bit("a") // false
    
### 将汉字、数字、字母转换为Unicode编码的方法 对于将汉字、数字、字母转换为Unicode编码,在JavaScript中有多种方法实现这一功能。一种常见的方式是利用`escape()`函数来处理字符串,该函数会尝试把非ASCII字符转化为百分号序列形式;然而更推荐的做法是使用内置的`charCodeAt()`或者`codePointAt()`配合自定义逻辑完成转化[^2]。 #### 使用 `charCodeAt()` `toString(16)` 函数 这种方法适用于基本多文种平面(BMP)内的字符,即大部分常用字符: ```javascript function stringToUnicode(str) { let result = []; for (let i = 0; i < str.length; i++) { const code = str.charCodeAt(i); result.push(`\\u${code.toString(16).padStart(4, '0')}`); } return result.join(''); } console.log(stringToUnicode("A1中")); // 输出: \u0041\u0031\u4e2d ``` 此代码片段遍历输入字符串中的每一个字符,并通过调用`charCodeAt()`获取其对应的Unicode数值表示法,再将其转换成十六进制并格式化为标准的`\uxxxx`样式输出。 #### 处理超出 BMP 的字符 (`codePointAt`) 当涉及到某些特殊符号或表情等不在基础多语言平面上的字符时,则需借助于ES6引入的新特性——`codePointAt()`: ```javascript function fullStringToUnicode(str){ let res=[]; [...str].forEach((ch)=>{ let hexCode=ch.codePointAt().toString(16); while(hexCode.length<4){hexCode="0"+hexCode;} if(hexCode.length>4){ res.push("\\u{"+hexCode+"}"); }else{ res.push("\\u"+hexCode); } }); return res.join(""); } console.log(fullStringToUnicode('😊')); // 输出: \u{1f60a} ``` 上述例子展示了如何针对所有可能遇到的情况提供支持,包括那些位于辅助平面以上的字符。注意这里采用了模板字符串语法`${}`来进行动态填充。 #### 反向操作:从Unicode编码到原始字符 如果要执行相反的过程即将给定的Unicode编码串解析回原本的文字表达,则可以直接依赖JavaScript引擎自动解码的能力或是手动编写相应的逆过程算法: ```javascript // 对应上面提到的第一种情况下的简单反向映射 eval('"'+stringWithUnicode+'"' ); // 或者更加安全可靠的办法如下所示: JSON.parse(JSON.stringify('\uXXXX')); ``` 以上就是关于在JavaScript环境下进行汉字、数字、字母同Unicode编码之间互相转变的一些实用技巧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值