【阅读】Javascript进阶阅读笔记 - 字符串篇

学习 · 01-28 · 61 人浏览

除了最常用的一些字符串替换拼接等操作,我们还应该从根本上认识字符串的一些误区

原因

计算机中,字符实际上是一个叫做Code Unit的东西,它占据16bit(2byte)的空间,所有的字符都会通过字符编码后变为Code Unit才进行存储和传输,在Js中,采用了UTF-16的编码方案,它主要的特点是所有字符占据的存储空间只会是2byte或者4byte, 而在比如UTF-8编码中还会存在1byte或者3byte的情况

主要问题

而正是因为存在2byte或者4byte的情况存在,所以Js中,对于字符长度的计算就出了问题:

string.length 是一个用来计算字符长度的方法,它的计算的依据则是按照字符的存储大小即:2byte作为一个长度`

而如果一个Unicode字符在经过UTF-16`编码后占据的是 4byte的空间就会出现这种情况,长度对应不上:

"𠯿".length // 2
除此之外,还有各种Emoji字符,每一个Emoji字符实际都是由多个不同长度的Code Unit组成,最终显示为一个Emoji表情的外观,所以对于字符串的位置操作也会被影响到

截取

前面提到过由于4byte的情况以及Emoji的影响,除了长度外,在截取上也会出现一些问题,比如我们常用的三种方法:

  1. 下标索引,对于索引外元素返回undefiend
  2. chatAt函数,对于索引外元素返回空字符
  3. at函数,还比较新,谷歌92后才支持,对于索引外元素返回undefined,并且如果是负数,则按照最大字符长度和负数相加取下标,如果超出索引范围还是返回undefined
"𠯿a"[2]        // "a"
"𠯿a".charAt(2) // "a"
"𠯿a".at(2)     // "a"
Array.from("𠯿a")[0] // "𠯿"
[..."𠯿a"][0]        // "𠯿"
Array.from("🧑🏾🎓a")[0] // "🧑" 对于Emoji完全无解
[..."🧑🏾🎓a"][0]        // "🧑"

区间

对于截取一个区间的字符串来说,也是相同的问题,最常用的就是substring、slice,前者会根据参数大小进行交换,且如果为负数则按照0处理。后者不会交换,但对于负数会进行字符串长度最大数相加使用

"今天天气晴朗🧑🏾🎓!".slice(0, 9)  // "今天天气晴朗🧑\uD83C"
"今天天气晴朗🧑🏾🎓!".slice(0, 10) // "今天天气晴朗🧑🏾"

总结

暂时没有特别好的办法来避免意外发生,也许可以根据字符的规范尽可能识别它避免发生错误(如产生了一个Emoji后,将Emoji在存储时转为一个能被正常处理的字符,在显示时在做一次转化)

除此之外包括但不限比如 indexOf、split、replace等方法,都会受到字符的存储影响,从而导致结果发生意料之外的情况。

Javascript进阶
Theme Jasmine by Kent Liao