js中的位运算

前言

在平常的工作中位运算用得比较少,一般用其他更容易理解得方式去达到相同目的。在计算机内部,一切运算最终都转化成二级制元算,直接使用二级制运算执行得效率是最高的。偶尔看到一道面试题,复习一下这方面知识,先来看一下这道面试题:

1
2
3
var a = 10;
a ^= (1<<4) - 1;
a的值

题目先放一放,看看js中有哪些位运算。

1. 位与(&)

真真为真,其余为假

1
2
3
4
5
6
9和10二进制位与运算

1001
& 1010
-------
1000

由于奇数的二进制末位为1,偶数为0,跟1的位与运算后,分别为1和0,因此可以用位与运算来判断奇偶数。

1
2
3
4
5
if(n & 1) {
console.log('n为奇数');
} else {
console.log('n为偶数');
}

2. 位或(|)

假假为假,其余为真

1
2
3
4
5
6
9和10二进制位或运算

1001
| 1010
-------
1011

整数与0的位或运算,都是本身。浮点数不支持位运算,过程中会自动转化成整数,利用这一点,可以将浮点数与0进行位或运算即可达到取整目的。

1
console.log(15.22 | 0); // 15

3. 位非(~)

真为假,假为真

1
2
3
4
5
6
7
8
9
9二进制位非运算

~ 0000000000000000 0000000000001001
-------取反
1111111111111111 1111111111110110
-------符号位不变,其余取反
1000000000000000 0000000000001001
-------加1
1000000000000000 0000000000001010

按位非操作,首先每一位取反,然后,第一位为负数符号位保持不变,剩余取反加1就是最后结果。

4. 异或(^)

相同为假,不同为真

1
2
3
4
5
6
9和10二进制异或运算

1001
| 1010
-------
0011

可以用于交换两个整数的值,不过一般很少这么用

1
2
3
4
5
6
var a = 3, b = 5;
a ^= b;
b ^= a;
a ^= b;
console.log('a:', a); // 5
console.log('b:', b); // a

5. 有符号左移(<<)

首位符号为不动,把32位二进制数字整体往左边移动指定位数,左边超出部分被舍去,右边补0。

1
2
3
4
5
9二进制有符号左移5位
9<<5
0000000000000000 0000000000001001
------
0000000000000000 0000000100100000

计算机内是这样位移计算的,实际应用计算我们可以通过公式:num * (2^n),即:9*Math.pow(2,5)

6. 有符号右移(>>)

首位符号为不动,把32位二进制数字整体往右边移动指定位数,右边超出部分被舍去,左边补0。

1
2
3
4
5
288二进制有符号右移5位
9>>5
0000000000000000 0000000100100000
------
0000000000000000 0000000000001001

计算机内是这样位移计算的,实际应用计算我们可以通过公式:num / (2^n),即:288/Math.pow(2,5)

7. 无符号右移(>>>)

符号为也跟着一起移动,这样,无符号右移会把负数的二进制当成整数的二进制码

1
2
3
4
5
4294967296二进制无有符号右移5位
4294967296>>>5
1000000000000000 0000000000000000
------
0000010000000000 0000000000000000

回归面试题

1
2
var a = 10;
a ^= (1<<4) - 1;

1<<4左移4位,即1*Math.pow(2, 4) == 16,则a ^= 15

1
2
3
4
5
10和15的异或运算
1111
^ 1010
.........
0101

0101二进制表示5,所以a的值位5