ES6+ 字符串的扩展
1. 前言
由于历史原因,在 JavaScript 创建之初,市面上的编码方式还是很混乱的,JavaScript 在创建之初,使用的是 1990 年公布的 UCS-2 的编码 方法 ,使用 2 个字节表示 1 个字符,那时 UTF-8、UTF-16、UTF-32 还没有完全确定。现在的 JavaScript 主要使用的是 UTF-16 来存储的。
但针对于纷繁复杂的网页字符是不能完全地覆盖的,在早期使用浏览器时,经常会在浏览器中选择字符串编码方式。那么有没有一种编码可以涵盖世界上的所有字符呢?答案是有的 ——Unicode。它是 一个 字符集,它的定义很简单,用 一个 码点 (code point) 映射 一个 字符。码点值的范围是从 U+0000 到 U+10FFFF,可以表示超过 110 万个符号。
所以后来的 ECMAScript 一直致力于 解决 历史遗留的问题和统一浏览器的编码方式。这时 ES6 出来了,对 Unicode 进行了加强,也修复了 ES5 中的问题。在 模版字符串 的小节中已经学习了关于字符串模板字符串的 内容 ,本节我们继续学习 ES6 中字符串其他的扩展。
2. Unicode
Unicode 只是 一个 符号集,它只规定了符号的二进制 代码 ,却没有规定这个二进制 代码 应该如何存储。所以出现了 Unicode 的多种存储方式,不同的实现导致了 Unicode 在很长一段时间内无法推广,而且本来 英文字母 只用 一个 字节存储就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个 英文字母 前都必然有二到三个字节是空,这对于存储来说是极大的浪费,文本 文件 的大小会因此大出二三倍,这是无法接受的。
首先我们来看下 一个 字符是怎么表示的,JavaScript 提供了 charCodeAt() 获取 指定位置的字符的值,返回的值在 0 到 65535 之 间的 整数。
var str = '' ; console . log ( str . charCodeAt ( ) ) ; // 24917 转成十六进制 0x6155 console . log ( str . charCodeAt ( ) ) ; // 35838 转成十六进制 0x8bfe console . log ( str . charCodeAt ( ) ) ; // NaN
看上面 代码 打印结果,并转成十六进制了,而 Unicode 表示是把前面的 0x 换成 u,这就是 Unicode 的表示。在 ES5 中还存在 一个 问题,实例如下:
let str = '?' ; console . log ( str . length ) // 2 ,str 是 Emoji 表情符 console . log ( str . charCodeAt ( ) ) // 55358 转成十六进制 0xd83e console . log ( str . charCodeAt ( ) ) // 56618 转成十六进制 0xdd2a console . log ( '\ud83e\udd2a' === '?' ) // true
上面的 代码 可以看到 str 是 一个 Emoji 的表情符号,使用length 属性 可以得到它的长度是 2,这完全不符合我们对这个字符串的定义。这就是 JavaScript 的编码问题。为 解决 charCodeAt() 方法 获取 字符码位 错误 的问题,新增 codePointAt() 方法 。
codePointAt() 方法 完全 支持 UTF-16,参数接收的是编码单元的位置而非字符位置,返回与字符串中给定位置对应的码位,即 一个 整数,如下实例:
let str = '?' ; console . log ( str . codePointAt ( ) ) // 129322 转成十六进制 0x1f92a => u1f92a console . log ( str . codePointAt ( ) ) // 56618 转成十六进制 0xdd2a => udd2a
上面的 代码 中,第二行打印位置 0 处的编码单元开始的码位,此例是从这个编码单位开始的两个编码单 元组 合的字符(四个字节),所以会打印出所有码位,即四字节的码位 129322 即 0x1f92a,大于 0xffff,也证明了是占四个字节的存储空间。
3. 字符串的遍历器接口
ES6 为字符串 添加 了可遍历接口,使得字符串可以被 for...of 进行循环遍历。如下实例:
var str = '网?' ; for ( let item of str ) { console . log ( item ) ; } // 慕 // 课 // 网 // ?
上面的 代码 中,最后 一个 是 emoji 表情字符,存储时占 4 个字节,但是通过 for...of 可以正确地迭代为 一个 字符。在 ES5 中则不行,我们来看个实例,把上面的字符串使用 ES5 中的 split 方法 把字符串转化成数组:
var str = '网?' ; console . log ( str . split ( '' ) ) // ["慕", "课", "网", "?", "?"]
从上面的 代码 中可以清晰地反映出表情字符是占四个字节,但是,ES5 不能把它当作 一个 字节来处理所以就会出现数组后两个元素的样子。这也是 ES5 存在的主要问题之一,可以通过迭代器对复杂的字符串进行正确的处理。
4. 小结
ES6 还提供了其他的字符串操作的 方法 ,接下来的几节专门讲解字符串中新增的 方法 ,更好地 解决 实际的开发问题。另外,ES6 还 增加 了模版字符串和带 标签 的模板字符串,在 模板字符串 中进行了讲解,遗忘的可以去看看。本节主要讲解了,字符串对 Unicode 的增强,还有对字符串 增加 了遍历接口,非常实用。