charAt()
语法
charAt(pos: number): string;
描述
用于获取一个字符串指定位置的字符。
当未传入参数时默认返回索引为 0 处的字符
当参数
小于 0
或大于 length -1
时返回空字符串此方法不能正确处理
4字节字符
示例
const twoBytesStr = 'yancey';
const fourBytesStr = '𝌆';
twoBytesStr.charAt(0); // 'y'
twoBytesStr.charAt(20); // ''
twoBytesStr.charAt(-1); // ''
// 无法正确处理4字节字符
fourBytesStr.charAt(0); // '�'
扩展
BMP(Basic Multilingual Plane)字符
JavaScript 使用 Unicode
进行字符编码。Unicode 标识符通过一个明确的名字
和一个整数
来作为它的码点/码位(code point)
。比如,“©️” 字符可以用版权标志
和码位U+00A9
来表示。
码点/码位为每一个字符提供一个全局唯一的标识符,一个码位映射一个字符,码位值的范围是从 U+0000 到 U+10FFFF,可以表示超过 110 万个符号。
Unicode 字符分为 17 组平面,每个平面拥有 2^16 (65,536) 个码位。每一个码位都可以用 16 进制 xy0000 到 xyFFFF 来表示,这里的 xy 是表示一个 16 进制的值,从 00 到 10。
而当 xy 是 00(码点范围是从 U+0000 到 U+FFFF)
的时候,也就是 Unicode 最前 2^16 (65,536) 个字符,被称为基本平面 BMP(Basic Multilingual Plane)
,最常见的字符都在这个平面上,这也是 Unicode 最先定义和最先公布的一个平面。
其余 16 个平面(U+010000 到 U+10FFFF)称为补充平面(supplementary planes, or astral planes)
,也称之为补充字符,相对于 BMP 字符而言,这些字符称之为非 BMP 字符。要区分是非 BMP 字符很简单:其码位需要超过 4 位 16 进制表示
UTF-16 和 UCS-2
UTF-16 对于 BMP 字符的码位,用 2 个字节进行编码;而非 BMP 字符的码位,用 4 个字节组成代理对(surrogate pair)
。
关于代理对:前两个字节称为高位代理或者顶部代理,范围在 0xD800 到 0xDBFF 之间;后两个字节称为低位代理或者尾部代理,范围在 0xDC00 到 0xDFFF 之间。
而 UCS(Universal Character Set),是一个 ISO 标准,UCS-2 用 2 个字节表示 BMP 字符的码点,UCS-2 是一个过时的编码方式,因为它只能编码基本平面 BMP 的码点,在 BMP 字符的编码上,与 UTF-16 是一致的,所以可以认为是 UTF-16 的一个子集。
而 JavaScript 一开始使用的正是UCS
,所以一些老的 API 是无法处理4字节字符
,因此 ES6 提供了codePointAt()
等新的 API,这些后面的篇章说。
fixedCharAt()
fixedCharAt()
通过字符串的索引
来获取相应位置的字符串。
const str = 'fixedCharAt('𝌆ab', 0)'
fixedCharAt(str, 0) // '𝌆'
fixedCharAt(str, 1) // 'a'
fixedCharAt(str, 2) // 'b'
function fixedCharAt(str, idx) {
var ret = '';
str += '';
var end = str.length;
var surrogatePairs = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
while (surrogatePairs.exec(str) != null) {
var li = surrogatePairs.lastIndex;
if (li - 2 < idx) {
idx++;
} else {
break;
}
}
if (idx >= end || idx < 0) {
return '';
}
ret += str.charAt(idx);
if (
/[\uD800-\uDBFF]/.test(ret) &&
/[\uDC00-\uDFFF]/.test(str.charAt(idx + 1))
) {
// Go one further, since one of the "characters" is part of a surrogate pair
ret += str.charAt(idx + 1);
}
return ret;
}