编程崽

登录

一叶在编程苦海沉沦的扁舟之上,我是那只激情自射的崽

进制转换和位运算符

进制转换和位运算符


位运算符是在数字底层(即表示数字的 32 个数位)进行操作的。

js 的位运算符有 7 个:

  • 逻辑位运算符:
    • & 位与
    • | 位或
    • ^ 位异或
    • ~ 非位
  • 移位运算符
    • << 左移
    • >> 右移
    • >>> 无符号右移

位运算符是用来对数字进行位运算,在对数字进行位运算时,无论两个数组原本是几进制的,都会先自动转为二进制,位运算执行完成后,再转为十进制返回。

前言

任意进制(2 ~ 36)字符串 转为 十进制数字

函数可解析一个其他进制的字符串,并返回一个十进制的整数。

parseInt(figure, radix)

  • figure:Number | String,要被解析的字符串
  • radix:可选,Number | String,表示要解析的数字的基数(进制),该值介于 2 ~ 36 之间,无该参数或该参数值为 0,则等同于值为 10

注意

  • 赋值一个数字时,js会自动做处理,比如:
    • 以 1-9 开头,正常十进制
    • 以 0b 开头,则会认为其是一个二进制数字,并自动转为十进制,比如 let a = 0b11,打印 a 的值为 3
    • 以 0o 开头(旧版本为 0 开头,语言已推荐使用 0o),则会认为其是一个八进制数字,并自动转为十进制,比如 let a = 011,打印 a 的值为 9
    • 以 0x 开头,同理,会认为其是一个十六进制数字,let a = 0x11,打印 a 的值为 17
  • radix 的值是 Number 还是 String,在结果上无任何区别
  • 当 figure 为数字格式时,会先自动转为十进制,再交由 parseInt 函数处理
  • 当 figure 为字符串格式时,figure 直接交由 parseInt 处理,中间不会有任何自动转换

代码说明:

js 复制代码
console.log(parseInt('0x10', 16)) // 16 解析:'0x10' 这个字符串,是一个 16 进制的,帮我转成十进制:1 * 16 + 0 = 16
console.log(parseInt(10, 16)) // 16,解析:10 这个数字,是一个 16 进制的,帮我转成十进制:1 * 16 + 0 = 16
console.log(parseInt(0o13, 16)) // 17
// 解析:
// 第一个参数 0o 开头,自动识别其为八进制,自动把 0o13 转为十进制的值为:11,变成:console.log(parseInt(11, 16))
// 此时第一个参数为11,再读取第二个参数值为16,相当于告诉程序:11这个数,是一个十六进制的数,帮我转为十进制
// 最终得到:1 * 16 + 1 = 17

console.log(parseInt(0x11, 16)) // 23
// 解析:
// 第一个参数 0x 开头,自动识别其为十六进制,自动把 0x11 转为十进制的值为:17,变成:console.log(parseInt(17, 16))
// 此时第一个参数为17,再读取第二个参数值为16,相当于告诉程序:17这个数,是一个十六进制的数,帮我转为十进制
// 最终得到:1 * 16 + 7 = 23

任意进制数字 转为 任意进制(2 ~ 36)字符串

NumberObject.toString(radix)

把一个 Number 对象(默认十进制,可根据写法自动判断)转换为一个 2 ~ 36 进制字符串,并返回结果

  • radix 可选,Number | String,表示要返回的数字的基数(进制),该值介于 2 ~ 36 之间,无该参数或该参数值为 0,则等同于值为 10

代码说明:

js 复制代码
console.log((0o110).toString('16')) // 48
// 解析:
// 第一个参数 0o 开头,自动识别其为八进制,自动把 0o110 转为十进制的值为:72,变成:console.log((72).toString('16'))
// 此时第一个参数为72,再读取第二个参数值为'16',相当于告诉程序:72这个数帮我转为十六进制
// 最终得到:48

console.log((0x10).toString('16')) // 10,解析同上
console.log((110).toString('16')) // 6e,此时第一个参数为110,再读取第二个参数值为'16',相当于告诉程序:110这个数帮我转为十六进制

& 位与

依次对比上下两位,两个数的二进制对应位置都是 1 时,当前位的运算结果为 1,否则为 0。

比如计算 10 & 12

js 复制代码
1010 // 10 的二进制
1100 // 12 的二进制
---- &
1000 // 结果 => 8

所以最终结果为 8。

上面有说,无论两个数组原本是几进制的,都会先自动转为二进制,所以,把 10 和 12 依次转为16进制:

10 & 12 等同于 0xa & 12 等同于 0xa & 0xc => 结果均为 8

| 位或

依次对比上下两位,两个数的二进制对应位置有一个值是 1 时,当前位的运算结果为 1,否则为 0。

比如计算 10 & 12

js 复制代码
1010 // 10 的二进制
1100 // 12 的二进制
---- |
1110 // 结果 => 14

^ 位异或

依次对比上下两位,两个数的二进制对应位置的值不同时,当前位的运算结果为 1,否则为 0。

比如计算 10 & 12

js 复制代码
1010 // 10 的二进制
1100 // 12 的二进制
---- ^
0110 // 结果 => 6

~ 非位

这一块涉及到一些二进制的拓展知识,我暂时还没来得及整明白,下面只大致写一下结果。

  1. 把运算数转换成 32 位数字
  2. 把二进制数转换成它的二进制反码(0 变为 1,1 变为 0)
  3. 把二进制数转换成浮点数 var iNum1 = 25 // 25 等于 00000000000000000000000000011001 var iNum2 = ~iNum1 // 转换为 11111111111111111111111111100110
js 复制代码
00000000000000000000000000001100 // 12 的二进制
---- ~
11111111111111111111111111110011 // => -13

<< 左移

把所有的值,向左侧移动几位,右侧新空出的位置补 0

比如计算 3 << 1

js 复制代码
00011 // 3 的二进制
00110 // 把最右侧的两个有效值 1 和 0,向左侧移动两位,右侧空出位置补 0
// 最终结果为 6

>> 右移

和左移相反,这个是向右移,最右端超出范围的数直接舍去

比如计算 3 >> 1

js 复制代码
00011 // 3 的二进制
00001 // 把最右侧的两个有效值 1 和 0,向右侧移动一位,右侧超出范围的数字直接舍去
// 最终结果为 1

>>> 无符号右移

比较难懂,同样是涉及到二进制一些拓展,暂未整理。