length、charAt()、charCodeAt()和 fromCharCode() 返回的结果都跟预期是一样的。这是因为在这个范围内,每个字符都是用 16 位表示的,而这几个方法 也都基于 16 位码元完成操作。只要字符编码大小与码元大小一一对应,这些方法就能如期工作。
这个对应关系在扩展到 Unicode 增补字符平面时就不成立了。问题很简单,即 16 位只能唯一表示 65 536 个字符。这对于大多数语言字符集是足够了,在 Unicode 中称为基本多语言平面(BMP)。为了 表示更多的字符,Unicode 采用了一个策略,即每个字符使用另外 16 位去选择一个增补平面。这种每个 字符使用两个 16 位码元的策略称为代理对。
在涉及增补平面的字符时,前面讨论的字符串方法就会出问题。比如,下面的例子中使用了一个笑 脸表情符号,也就是一个使用代理对编码的字符:
// "smiling face with smiling eyes" 表情符号的编码是 U+1F60A // 0x1F60A === 128522
let message = "ab☺de";
console.log(message.length); // 6
console.log(message.charAt(1)); // b
这些方法仍然将 16 位码元当作一个字符,事实上索引 2 和索引 3 对应的码元应该被看成一个代理 对,只对应一个字符。fromCharCode()方法仍然返回正确的结果,因为它实际上是基于提供的二进制 表示直接组合成字符串。浏览器可以正确解析代理对(由两个码元构成),并正确地将其识别为一个 Unicode 笑脸字符。
为正确解析既包含单码元字符又包含代理对字符的字符串,可以使用 codePointAt()来代替 charCodeAt()。跟使用 charCodeAt()时类似,codePointAt()接收 16 位码元的索引并返回该索引 位置上的码点(code point)。码点是 Unicode 中一个字符的完整标识。
let message = "ab☺de";
console.log(message.codePointAt(1)); // 98
console.log(message.codePointAt(2)); // 128522
console.log(message.codePointAt(3)); // 56842
console.log(message.codePointAt(4)); // 100 8
注意,如果传入的码元索引并非代理对的开头,就会返回错误的码点。这种错误只有检测单个字符 的时候才会出现,可以通过从左到右按正确的码元数遍历字符串来规避。迭代字符串可以智能地识别代 理对的码点:
console.log([..."ab☺de"]); // ["a", "b", "☺", "d", "e"]
与 charCodeAt()有对应的 codePointAt()一样,fromCharCode()也有一个对应的 fromCodePoint()。 10 这个方法接收任意数量的码点,返回对应字符拼接起来的字符串:
标签:字符,console,log,16,js,字符串,message,处理函数,codePointAt From: https://blog.51cto.com/u_16273048/9194537