跳到主要内容

JS 中的位运算

长念
长念阅读约 5 分钟6 年前发布3 年前编辑
本文涉及内容均为二进制操作
提示

在 JavaScript 中数字存储均为基于 IEEE 754 标准的双精度 64 位的浮点数,但是在位运算时都会当作 32 位进行运算,所以大于 2^32 - 1 的数字在位运算时会丢失高位。

(有符号)左移 <<

num << n:将 num 转为二进制,左移 n 位(输出的结果是十进制的)

10 << 2; // 40
// 10的二进制是 1010,左移两位是 101000,转为十进制就是 40

-10 << 2; // -40

关于这个负数怎么移位 (以 -10 << 2 为例) :

序号操作数值表示
1转为二进制10000000 00000000 00000000 00001010
2无符号整数00000000 00000000 00000000 00001010
3取反+111111111 11111111 11111111 11110110
4移位(低位补 0)11111111 11111111 11111111 11011000
5-1 取反00000000 00000000 00000000 000101000
6补符号位10000000 00000000 00000000 000101000
7转为十进制-40

(有符号)右移 >>

num >> n:将 num 转为二进制,右移 n 位(输出的结果是十进制的)

10 >> 2; // 2
// 10的二进制是 1010,右移两位是 10,即 2

-10 >> 2; // -3

负数的情况同样(以 -10 >> 2 为例) :

序号操作数值表示
1转为二进制10000000 00000000 00000000 00001010
2无符号整数00000000 00000000 00000000 00001010
3取反+111111111 11111111 11111111 11110110
4移位(高位补 1)11111111 11111111 11111111 11111101
5-1 取反0000000000 00000000 00000000 000011
6补符号位1000000000 00000000 00000000 000011
7转为十进制-3

(无符号)右移 >>>

num >>> n:将 num 转为二进制,右移 n 位(输出的结果是十进制的)

10 >>> 2; // 2
// 10的二进制是1010,右移两位是10,即2

-10 >>> 2;
1073741821;

负数情况同样(以 -10 >>> 2 为例) :

序号操作数值表示
1转为二进制10000000 00000000 00000000 00001010
2无符号整数00000000 00000000 00000000 00001010
3取反+111111111 11111111 11111111 11110110
4移位(高位补 0)00111111 11111111 11111111 11111101
5转为十进制1073741821

00111111 11111111 11111111 11111101 这个数转为十进制是不好算的,可以间接计算: 2 ** 31 - 2 ** 30 - 3 :

  10000000 00000000 00000000 00000000
- 01000000 00000000 00000000 00000000
- 00000000 00000000 00000000 00000011

按位与 &

num1 & num2:转为二进制,按位相与: 同 1 则 1, 符号位参与运算

1&1=11&0=00&1=00&0=0
10 & 2; // 2
/*
10的二进制是 1010
2的二进制是 0010
按位与的结果是 0010,也就是 2
*/

// 连同符号位一起运算
-10 & 2; // 2
10 & -2; // 10
-10 & -2; // -10

按位或 |

num1 & num2:转为二进制,按位相或: 同 0 则 0,符号位参与运算

1|1=11|0=10|1=10|0=0
10 | 2; // 10
/*
10的二进制是 1010
2的二进制是 0010
结果是1010,也就是10
*/

//连同符号位一起运算
-10 | 2; // -10
10 | -2; // -2
-10 | -2; // -2

按位非 ~

~num:转换为二进制按位取反: 0 变 1,1 变 0,符号位参与运算

~10; // -11
/*
10的二进制是0000 1010
按位取反后是1111 0101
对应的是 -11 的补码:1111 0101 减去 1 得到 1111 0100 取反(符号位不运算)得到 1000 1011
*/

负数补码是由原码 取反+1 后得到的,所以通过补码可以反推原码,注意求原码的过程符号位不参与运算。

异或 ^

num1^num2:转为二进制,按位异或: 异则 1,同则 0,符号位参与运算

1^1=01^0=10^1=10^0=0
10 ^ 2; // 8
/*
10的二进制是 1010
2的二进制是 0010
结果是1000,也就是 8
*/

//连同符号位一起运算
-10 ^ 2; //-12
10 ^ -2; // -12
-10 ^ -2; //8