知识点1—进制转换
10进制转换为其他进制
在Number原型链上存在方法toString
方法,用于将10进制转换为其他进制(2-36)
语法
// 指定要用于数字到字符串的转换的基数 (从 2 到 36)。如果未指定 radix 参数,则默认值为 10
num.toString([radix])
tips: 在使用数字调用方法时,建议加(),不然数字后面的点会被认为是小数点而不是方法调用。
返回值:对应进制的字符串
(33).toString() // '33'
(20005).toString(2) // '100111000100101'
(0x16).toString(16) // '16'
注: 若是没有标注,num默认为10进制
以0x开始的数据表示16进制
负数
Number原型链上的toString方法将10进制转化成其他进制尽是在num为正数时起作用
(-1000).toString(2) // '-1111101000' 但是实际的值为 0000011000
负数的十进制转化为2进制
负数在内存中是以补码
的形式存储的,因此若是计算负数的二进制,需要先计算正值的二进制然后计算期补码;
计算补码: 先对二进制值逐位取反再对取反后的二进制数加1得到补码;
举例说明:-100转化为二进制
- [1] 100转化为二进制为 1100100
- [2] 逐位取反 0011011
- [3] 加1 0011111
- -100的二进制为 0011111
其他进制转化为10进制
其他进制转换为10进制的规则为:按权展开相加
16进制转化为10进制
- 在16进制中ABCDEF表示的分别是10,11,12,13,14,15;
- 从右向左按权展开相加
- eg:52E4转换为10进制过程为
52E4 = 5 * 10^0 + 2 * 10^1 + 14 * 10^2 + 4 * 10^3
= 5+32+3584+16384
= 20005
2进制转化为10进制
- 从右向左按权展开相加
- eg:
知识点2—ASCII码与Unicode
ASCII码
-
在计算机内部,所有信息都是以
二进制
(0,1)进行存储的。 -
每一个二进制
位
(bit)有0和1
两种状态- 一个
字节
有8个二进制位,八个二进制位就可以组合出256种状态。 - 也就是说,一个字节一共可以用来表示256种不同的状态。
- 一个
-
美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码,一直沿用至今。
- ASCII 码一共规定了127个字符的编码,比如空格space是32(二进制00100000),大写的字母A是65(二进制01000001)。
- 这127个符号(包括32个不能打印出来的控制符号),
只占用了一个字节的后面7位,最前面的一位统一规定为0
。 - 以下这些编号呢就被称为
码点
,码点可以称为这些字符的身份证号码
非ASCII
-
英语用127个符号编码就够了,但是用来表示其他语言,127个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用 ASCII 码表示。
-
于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。
-
这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。
-
但是,这里又出现了新的问题 -> 不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。
-
但是不管怎样,所有这些编码方式中,
0--127表示的符号是一样的
,不一样的只是128--255的这一段
。 -
至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是 GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示 256 x 256 = 65536 个符号。
Unicode
正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。
可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode
,就像它的名字都表示的,这是一种所有符号的编码
被称为万国码。
tips:知道为什么 txt文件使用vscode打开会乱码吗?
原因:vscode默认使用的编码方式为utf-8而txt文件的编码方式为 GB2312编码格式,因此会乱吗;
解决:若是想txt文件在vscode打开,在当前页面修改编码方式
unicode获取码点与对应的字符
fromCharCode
formCharCode是String的静态方法,用于将 Unicode 编码转为一个字符!
语法:String.fromCharCode(num1[, ...[, numN]])
- num1, …, numN : 一个或多个 Unicode 值,即要创建的字符串中的字符的 Unicode 编码 (范围介于0~65535,因为0~65535是unicode的码点,超出就没有意义了)
返回值:返回一个长度为 N 的代表 Unicode 编码的字符;
举例说明:
String.fromCharCode(65) // 'A'
String.fromCharCode(25105) // '我'
charCodeAt
语法:string.charCodeAt(index)
返回值:指定 index 处字符 对应的Unicode码点(取值范围为0-65535)
UTF-32(不推荐)
UTF-32统一使用4个字节表示一个字符,虽然这样可以使得全世界使用统一的编码方式,但是占用存储空间,通信效率变低。
比如说ASCII码, 每个ASCII码表示的字符都需要在前面3个字符补足0才行;及时时中文BGK表示的字符前面都需要使用2个字符补足0才行,这降低了通信效率,因此不被采纳。
UTF-8(普遍使用)
互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一。
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8 的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的
。
2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
下表总结了编码规则,字母x表示可用编码的位。
跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
下面,还是以汉字我为例,演示如何实现 UTF-8 编码。
我的Unicode为25105,转换为十六进制为6211(处于第三行),转换为二进制为 110001000010001;因此我使用UTF-8编码应该是
从右向左按照6位一组进行划分 110 001000 010001
划分完毕之后添加到 1110xxxx 10xxxxxx 10xxxxxx中去,若是空却使用0补齐
结果为 11100110 10001000 10010001
转换为16进制为 E68891
知识点3—URL编码/解码
[1] 为什么要进行URL编码
先看如下案例
-
发送请求去获取数据,请求的url如下
https://www.baidu.com?wd=hello word&name=超超&age=18&sex=女
但是在浏览器打开,实际请求的url变为如下
https://www.baidu.com?wd=hello%20word&name=%E8%B6%85%E8%B6%85&age=18&sex=%E5%A5%B3
-
为什么url会自己发生改变呢?
- 这是由于在网络请求中,只能采用
A-Z a-z 0-9 以及字符 - _ . ! ~ * ' ( )
这些字符,若是遇到汉子或一些特殊字符,就会先进行URL编码再发送请求。
- 这是由于在网络请求中,只能采用
-
看到这里或许会觉得这也无所谓,只要在接收到url之后再进行解码即可!但是问题在于标准国际组织并没有规定具体的编码方法,而是将决定权交给了
浏览器
,也就是说不同的浏览器的编码方式可能会不同,那在解码时就需要进行判断比较麻烦 —> 若是使用js在发送请求之前对URL进行编码就实现了编码方式的统一!
[2] encodeURIComponent方法
-
作用:encodeURIComponent函数可把字符串作为 URI 组件进行编码
-
语法:
encodeURIComponent(str);
-
编译过程:该方法不会对 ASCII 字母和数字进行编码,也不会对这些 安全的ASCII 标点符号(
- _ . ! ~ * ’ ( )
)进行编码,只会对特殊字符进行编码。- 安全ASCII字符:保留;
- 非安全ASCII字符:使用
utf-8
对其进行编码得到对应的字节,然后对每个字节进行百分号编码
(将16进制的0x替换为%)- 举例说明:‘中文’转化为utf-8为 0xE4 0xB8 0xAD 0xE6 0x96 0x87, 进行百分号编码最终结果为 %E4 %B8 %AD %E6 %96 %87
encodeURIComponent('中文') // '%E4%B8%AD%E6%96%87'
- 举例说明:‘中文’转化为utf-8为 0xE4 0xB8 0xAD 0xE6 0x96 0x87, 进行百分号编码最终结果为 %E4 %B8 %AD %E6 %96 %87
- 举例说明
// 不会对数字与英文字符进行编码 encodeURIComponent("156xxxxxxxx") // '156xxxxxxxx'
// 会对特殊字符进行编码 encodeURIComponent("hello word") // 'hello%20word'
// 会对非AscII码进行编码 encodeURIComponent("中国真棒") // '%E4%B8%AD%E5%9B%BD%E7%9C%9F%E6%A3%92'
- 使用场景:
- 在使用
url进行参数传递
的时候,当参数出现空格这样的特殊字段,后台只可以读取到空格前的内容,后面内容丢失,造成数据读取失败; 但是如果用encodeURIComponent函数将这些特殊字符进行转义,后台就可以成功读取传递的数据了; - 用于base编码过程;
- 在使用
[3] decodeURIComponent
decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码
举例说明:
//'%E4%B8%AD%E5%9B%BD%E7%9C%9F%E6%A3%92'
encodeURIComponent('中国真棒')
// '中国真棒'
decodeURIComponent('%E4%B8%AD%E5%9B%BD%E7%9C%9F%E6%A3%92')
知识点4—base64编码/解码
base64定义
所谓Base64,就是选出64个字符
- 小写字母a-z、
- 大写字母A-Z、
- 数字0-9、
- 符号"+“、”/"
- 再加上作为垫字的"="
实际上是65个字符作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。
使得二进制数据在解释成 radix-64 的表现形式后能够用 ASCII 字符串
的格式表示出来。
base64转换规则
base64转换规则具体来说可以分为四步:
第一步,将每三个字节作为一组,一共是24个二进制位。
第二步,将这24个二进制位分为四组,每个组有6个二进制位。
第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节。
第四步,根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值。
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w
15 P 32 g 49 x
16 Q 33 h 50 y
因为,Base64将三个字节转化成四个字节,因此Base64编码后的文本,会比原文本大出三分之一左右。
举例说明
举一个具体的实例,演示英语单词Man如何转成Base64编码。
-
第一步,“M”、“a”、"n"的ASCII值分别是77、97、110,对应的二进制值是01001101、01100001、01101110,将它们连成一个24位的二进制字符串010011010110000101101110。
-
第二步,将这个24位的二进制字符串分成4组,每组6个二进制位:010011、010110、000101、101110。
-
第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节:00010011、00010110、00000101、00101110。它们的十进制值分别是19、22、5、46。
-
第四步,根据上表,得到每个值对应Base64编码,即T、W、F、u。
因此,Man的Base64编码就是TWFu。
字节数不足三的情况
如果字节数不足三,则这样处理:
-
a)二个字节的情况:将这二个字节的一共16个二进制位,按照上面的规则,转成三组,最后一组除了前面加两个0以外,后面也要加两个0。这样得到一个三位的Base64编码,再在末尾补上一个"="号。
- 比如,“Ma"这个字符串是两个字节,可以转化成三组00010011、00010110、00010000以后,对应Base64值分别为T、W、E,再补上一个”="号,因此"Ma"的Base64编码就是TWE=。
-
b)一个字节的情况:将这一个字节的8个二进制位,按照上面的规则转成二组,最后一组除了前面加二个0以外,后面再加4个0。这样得到一个二位的Base64编码,再在末尾补上两个"="号。
- 比如,“M"这个字母是一个字节,可以转化为二组00010011、00010000,对应的Base64值分别为T、Q,再补上二个”="号,因此"M"的Base64编码就是TQ==。
base64编码对应的方法
btoa
btoa是binary to ascii的缩写;
作用:btoa是window对象的方法,作用是将二进制数据
或ASCII字符串
转换成一个base64编码过的ASCII字符串
。
语法:btao(stringToEncode)
- stringToEncode 是一个需要编码的二进制字符串;
- 传入的字符串将视为一个二进制字符串 -> 将字符串中的每一个字节都视为一个二进制数据字节;
- 因此:每个字符
只能使用一个字节
表示,若是其中包含了需要使用超过一个字节才能表示的字符,你就会得到一个错误,因为这个字符串不能被看作是二进制数据; - 因此btoa能够编码
(全部的)ASCII
字符却不能编码(超过一个字节的)Unicode
字符。
举例说明:
- ASCII字符串能够正常编码;
var str = "hello world"; var demo = btoa(str); console.log(demo);// aGVsbG8gd29ybGQ=
-
Uniconde字符串中存在超过1个字节的字符则不能正常编码,会报如下错误:
var str = "中国真棒"; var demo = btoa(str); console.log(demo);
-
若是想要将Unicode字符编码为base64,在编码之前还需要使用
encodeURIComponent
方法将Unicode字符进行转换,再进行base64编码;
atob
atob:是ascii to binary的缩写
作用: atob是window的方法,作用是对经过 base-64 编码的字符串进行解码
var demo = "aGVsbG8gd29ybGQ=";
var str = atob(demo);
console.log(str);//hello world
若是在加密过程中使用了encodeURIComponent方法进行编码就要在解码过程中使用decodeURIComponent
进行解码
重点-base64编码解码方法封装
js-base64编码
encode (str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
function toSolidBytes (match, p1) {
return String.fromCharCode('0x' + p1)
}))
}
js-base64解码
decode (str) {
return decodeURIComponent(atob(str).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
}).join(''))
}
插件-js-base64
该插件的原理就是上述base64编码解码过程
安装:npm install --save js-base64
引入:
import { encode, decode } from 'js-base64';
使用
// 加密
encode(encodeURIComponent('张三')) // '5byg5LiJ'
// 解密
decode(decodeURIComponent('5byg5LiJ')) // 张三
六个方法的综合应用(插件的原理)
encode (str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
function toSolidBytes (match, p1) {
return String.fromCharCode('0x' + p1)
}))
}
[1] 对“中国真棒”进行base64进行编码
btoa(“中国真棒”)
- 报错-> 不能对超过1个字节的字符进行编码
[2]将“中国真棒”拆解为多个单字节的字符串
- [2.1]将字符编译为单个字节的字符
encodeURIComponent('中国真棒') // '%E4%B8%AD%E5%9B%BD%E7%9C%9F%E6%A3%92'
- [2.2]将编译后的字符转换为Unicode
'%E4%B8%AD%E5%9B%BD%E7%9C%9F%E6%A3%92'.replace( /%([0-9A-F]{2})/g, function toSolidBytes(match,p1){ return String.fromCharCode('0x' + p1) // 将UTF-16的数转化为对应的Unicode 编码的字符 } ) // 'ä¸å\x9B½ç\x9C\x9Fæ£\x92'
[3] 将单子节自符进行base 64编码
btoa('ä¸å\x9B½ç\x9C\x9Fæ£\x92') //'5Lit5Zu955yf5qOS'
[4] 对btoa方法编码后的字符进行解码
atob('5Lit5Zu955yf5qOS') // 'ä¸å\x9B½ç\x9C\x9Fæ£\x92'
[5] 将单字节字符还原-》还原为十六进制的转义序列
'ä¸å\x9B½ç\x9C\x9Fæ£\x92'.split('').map(item => '%'+('00'+item.charCodeAt(0).toString(16)).slice(-2)).join('')
// '%e4%b8%ad%e5%9b%bd%e7%9c%9f%e6%a3%92'
[6] 由于改字符使用过 encodeURIComponent编码过,因此使用decodeURIComponent进行解码
decodeURIComponent('%e4%b8%ad%e5%9b%bd%e7%9c%9f%e6%a3%92') // '中国真棒'