#先来看看一个很神奇的现象
emoji的表情的长度竟然是2???
究其原因要从es的字符集和编码方式谈起
一、ES的发展历史
JS的语言采用Unicode字符集,但是只支持一种编码方式
扫盲:utf8和utf16是unicode的一种编码方式,不是字符集,是为方便Unicode字符集方便在网络传输的一种加密方式
但是JS采用的编码方式既不是UTF8也不是UTF16,更不是UTF32,而是UCS-2
UTF32规定了每个字符串的码点使用4个字节表示即32位,虽然转换方式简单,但是十分浪费空间,ASCII编码使用 1字节,相比而言要大四倍,因此HTML5标准铭文规定网页不许使用32编码
如 U+0000 = 0x00 00 00 00 4字节
U+597D = 0x00 00 59 7D 不足的前面用0填充
这要从ES的诞生时间线说起:
1.1988年Unicode团队成立(指字符集)
2.次年1989年UCS团队成立(指字符集)
3.1990,UCS-2编码发布(指编码方式)
4.1991年两者合并字符集为Unicode(合并字符集)
5.1995Js诞生
6.1996UTF-16发布,取代UCS-2(指编码方式)
也就是说JS语言诞生的时候还没有UTF16编码!!
二、UCS-2编码的特点
UCS的开发进度快于Unicode,1990年就公布了第一套编码方法UCS-2,使用2个字节表示已经有码点的字符。
TF-8是一种变长的编码方法,字符长度从1个字节到4个字节不等。越是常用的字符,字节越短,最前面的128个字符,只使用1个字节表示,与ASCII码完全相同。
UTF-16编码介于UTF-32与UTF-8之间,同时结合了定长和变长两种编码方法的特点。它的编码规则很简单:基本平面的字符占用2个字节,辅助平面的字符占用4个字节。也就是说,UTF-16的编码长度要么是2个字节(U+0000到U+FFFF),要么是4个字节(U+010000到U+10FFFF)。
上述概括:
在Unicode中,最前面的65536个字符(包括最常见的所有字符)称为基本平面(BMP),码点(16进制)从U+0000---U+FFFF,目前共有17个平面,剩下的称为辅助平面(SMP)(U+010000到U+10FFFF)
UTF-16:当在BMP范围内的字符编码为2个字节,SMP为4个字节
UCS-2:全部二个字节,一视同仁
那么问题来了?超过2个字节的怎么处理
既然不属于UCS-2,那就当两个字符来看喽~~
再回来看刚开始提出的问题
我们使用 charCodeAt查看🎾的UTF16编码
charCodeAt() 方法返回0到65535之间的整数,表示给定索引处的UTF-16代码单元
Unicode默认16禁止,再利用toString()转为16进制
但在——例如 Unicode 编码单元 > 0x10000 的这种——不能被一个 UTF-16 编码单元单独表示的情况下,只能匹配 Unicode 代理对的第一个编码单元
所以上面默认是第一个编码单元,完善为
即🎾的UTF16编码为4个字节的0xD83C DFBE
所以JS超过2个字节,当作两个字符来看,会把它当作 U+D83C和U+DFBE两个来看
查询Unicode编码得两个都为�
验证
这也就是为什么length会失效
仅仅只是length函数吗?
以slice为例
基本上所有的字符串函数在对4字节码点的字符串表现出奇怪的现象
虽然很少遇到但还是以防万一
总结来源:http://www.ruanyifeng.com/blog/2014/12/unicode.html