前言
使用 slice 截取字符串出现如下问题

分析
JS 的字符串很早之前使用 UCS-2 格式,每个字符固定16位,一码元。它只能表示 Unicode 的基本多语言平面(BMP),即 U+0000 到 U+FFFF 范围的字符,无法处理码点大于 U+FFFF 的字符。
现在采用的 UTF-16 是 UCS-2 的扩展,支持每个字符既可以是16位(一码元)也可以是32位(两码元)。
𠮷:码点大于 U+FFFF,两码元,所以占了两字节,而JS中字符串的length和下标针对的是码元,所以当slice没有完全截取出「𠮷」时就出现了这个问题。


解决
方法一:转为数组
const str = "𠮷abc";
const charArray = Array.from(str); // 按字符将字符串转换为数组
console.log(charArray.slice(1).join("")); // 正确输出 "abc"
方法二:对比码点值
ES6的codePointAt可以获取字符的码点

将码点与最大16位进行比较,如果大于证明该字符占两码元

String.fromCodePoint可以将码点转为字符串

String.prototype.slicePlus = function (start, end) {
let result = ""
let pIndex = 0 // 码点位置
let cIndex = 0 // 码元位置
while (1) {
if (pIndex >= end && cIndex >= this.length) {
break
}
const point = this.codePointAt(cIndex)
if (pIndex >= start) {
result += String.fromCodePoint(point)
}
pIndex++
cIndex += point > 0xffff ? 2 : 1
}
return result
}


被折叠的 条评论
为什么被折叠?



