计算机:二进制的世界
1110 0100 1011 1101 1010 0000 1110 0101 1010 0101 1011 1101
上面一行字就是“你好”在计算机中的表示方式
下面就来聊一聊计算机存储的过程
第一步:内存如何存储 0 和 1 ?
- 存储
图中模拟计算机存储 0 和 1 的过程,所示的是一个8*8的晶体管方阵,可以将每一个圆点当作看成是一个小电池,当需要存储一串二进制信息时,竖向存选中(1或0),横向输送电量,1就充电(显示红色),0就不充电(显示白色)。 - 读取
晶体管存电很少,耗电很快(ms),需要多次刷新,在耗尽电量之前进行充电(ns),要保证1还是1(电量大于50%就是1,电量小于50%就是0)。
CPU的赫兹就是每秒刷新多少次
通过计算机能够存储 0 和 1,程序员将世间万物的信息存进了计算机。
第二步:如何存储数字?
十进制转二进制
- 正数存储
37(10)=3 * 10 ^1 + 7* 10^0 = 32 + 4 + 1=1 * 2^5 + 1 * 2^2 + 1 * 2^0=100101(2) - 负数存储
由于计算机只能存储0和1,负号不能存储,负数会以补码形式存储
-37(10) == -100101(2) - 小数存储
把十分之一为底的数变成以二分之一为底的数,由于计算机只能存储0和1,小数会以浮点数的形式存储
0.75(10) = 0.5 + 0.25 = 1 * 1/2 + 1 * 1/4 = 0.11(2)
为了方便书写,一般会将二进制数写为十六进制数
第三步:如何存储字符
将每个字符编号,外国人将每个字符进行了编号0~127共128个ASCII码值。
ASCII美国信息交换标准代码
如果你想储存 a,那么就储存 97(10) 对应的二进制
a -> 0110 0001(2) -> 61(16)
如果你想储存 字符1,那么就储存 49(10) 对应的二进制
1 -> 0011 0001(2) -> 31(16)
为方便书写将二进制转成十六进制
第四步:如何存储中文
我国制定了常用中文字符集GB 2312 中国国家标准字符集)
而后微软将一些生僻字日韩字符等加入后推出了
GBK字符集
第五步:如何存储所有字符
将全球文字统一到一个表里面,包括中日韩文字、藏文、盲文、楔形文字、颜文字:-)、绘文字😂
第六步:如何将Unicode存到计算机里
Unicode 需要使用 32 位(4字节)来存储字符,他的存储方式如下
//低效率方式
a -> 0000 0000 0000 0000 0000 0000 0110 0001 = 0061
你 -> 0000 0000 0000 0000 0100 1111 0110 0000 = 4F60
由于其表示简单的字符时也使用4个字节,浪费了很多资源,为提高效率,人们开始使用UTF-8,UTF-8是Unicode存到计算机的一种编码方式,它不是字符集,它可以用来表示Unicode标准中的任何字符。
//高效率方式 UTF-8
a -> 01100001
你 -> 11100100 10111101 10100000
- 像“a”这种较短的字符(小于七位的),我们可以直接在前面补零表示
- 像“你”这种长的字符,由于计算机读取时无法弄清楚是存储了一个 由两个一字节组成的字符还是一个由两字节组成的字符,解决步骤(UTF-8):
- 我们从高位依次划分6个字符进行分组,直到分出的组不足6个。即:0100 111101 100000
- 分别在每一组前面补全读取这一串二进制信息的规则,即:1110XXXX 10XXXXXX 10XXXXXX
- 1110XXXX:111表示计算机需要读取3个字节,每个字节的开头都是10,10+XXXXXX、10+XXXXXX: 所以后两个分组的开头也补上10,说明是和第一个字节一起的,组成一个字符。只有X才是原二进制有效的数据
UTF-8
UTF-8 是一种编码方式,不是字符集,更高效的将Unicode存储到计算机中
现实问题
编码问题
JavaScript 使用了 Unicode 字符集,但没有使用 UTF-8 编码
JavaScript使用 UCS-2 编码,因为1995年 UTF-16还没有发明出来,JavaScript也不想使用 UTF-32
后果
ES5 无法表示 \uFFFF之后的字符(如 \u1D306),某些情况下会出bug
语言层面的问题,需要留心。