一、整数的二进制表示
js中整数都是以二进制补码的形式存储,至于为什么是补码形式,后面会有解释。假设以8位二进制表示一个整数(一般是32位和64位,这里为了方便演示使用8位表示)。
最高位是符号位,0表示正数,1表示负数。
1、原码
原码就是十进制和二进制的直接转换,如3的原码是00000011,-3的原码是10000011。
可以看出8位二进制可以表示的正整数范围是00000001~01111111,即~(
=127);负整数范围是10000001~11111111,即-
~-(
)=-127;另外正零和负零的表示不相同。
2、反码
正数的反码就是其原码本身,即3的反码也是00000011。
负数的反码是将其符号位除外的其余位取反,即-3的反码是11111100。
3、补码
正数的补码同样和其原码相同,即3的补码也是00000011。
负数的补码是其反码+1,即-3的补码是11111100+1=11111101;比较特殊的是-0的补码是11111111+1=00000000,与+0的补码相同;另一个特殊的是补码中10000000用来表示-128。
计算机使用补码存储整数的优势:
- +0和-0的表示相同,简化判断;
- 加减法都可以通过加法运算完成,简化运算电路;例如3-2,换算成加法运算3+(-2),对应的三种码的计算结果如下:
复制原码:3+(-2) = 00000011+10000010 = 10000101 = -5 != 1 反码:3+(-2) = 00000011+11111101 = 00000000 = 0 != 1 补码:3+(-2) = 00000011+11111110 = 00000001 = 1
二、js中的位运算
js中的位运算都在整数上进行。
1、按位与(&)
运算符在两个操作数对应的二进位都为 1
时,该位的结果值才为 1。
例如:3&3 = 00000011&00000011 = 00000011 = 3。
作用:
- 清零特定位。如清零前四位可以与-16(补码为11110000)按位&,31&(-16) = 00011111&11110000 = 00010000
- 提取某数中的指定位。如提取前四位可以与15按位&,31&15 = 00011111&00001111 = 00001111
- 检查位1。通过将一个数减去1后再与原数进行按位与运算,可以将该数二进制表示中最右边的一个1变成0。这种方法可以用来计算一个数的二进制表示中有多少个1
2、按位或(|)
运算符在其中一个或两个操作数对应的二进位为 1
时,该位的结果值为 1。
例如:4&3 = 00000100&00000011 = 00000111 = 7。
作用:
常用于位掩码操作、权限设置等场景
3、按位异或(^)
运算符在两个操作数有且仅有一个对应的二进制位为 1
时,该位的结果值为 1。
例如:7&3 = 00000111&00000011 = 00000100 = 4。
作用:
-
翻转特定位。即1变为0,0变为1
-
实现两个值的交换。即假设有A、B两个变量,经过A = A ^ B,B = A ^ B,A = A ^ B三步操作后变量值交换
4、按位非(~)
按位非运算符(~
)将操作数的位反转。
例如:~7 = ~00000111 = 11111000(补码) = -8。
作用:用于
位操作和加密算法。
5、左移(<<)
将第一个操作数向左移动指定位数,左边超出的位数将会被清除,右边将会补零。
例如:7<<2 = 00000111<<2 = 00011100 = 28。
作用:
数值放大。
左移运算可以将一个数乘以2的n次方,其中n是移动的位数
6、有符号右移(>>)
将一个操作数的二进制表示形式向右移动指定位数,该操作数可以是数值或者 BigInt 类型。右边移出位被丢弃,左边移出的空位补符号位(最左边那位)。
例如:7>>2 = 00000111>>2 = 00000001 = 1。
作用:
数值缩小。
右移n位相当于除以,同时舍去其小数部分。
7、无符号右移(>>>)
(零填充右移)将左操作数计算为无符号数,并将该数字的二进制表示形式移位为右操作数指定的位数。向右移动的多余位将被丢弃,零位从左移入。其符号位变为 0
,因此结果始终为非负数。
例如:-7>>2 = 11111001>>2 = 00111110 = 62。(按8位表示是62,如果按32位即右移结果为1073741822)
作用:
-
位移操作:将数字的二进制表示向右移动指定的位数。
-
无符号处理:在右移时,左侧填充0,而不考虑原始数字的符号位。这意味着即使是负数,在使用
>>>
运算后也会被当作正数处理,最高位(符号位)会被0填充。