JavaScript位运算应用场景
# 位运算
Operator | Usage | Description |
---|---|---|
按位与 AND | a & b | 在 a,b 的位表示中,每一个对应的位都为 1 则返回 1,否则返回 0. |
按位或 OR | a | b | 在 a,b 的位表示中,每一个对应的位,只要有一个为 1 则返回 1,否则返回 0. |
按位异或 XOR | a ^ b | 在 a,b 的位表示中,每一个对应的位,两个不相同则返回 1,相同则返回 0. |
按位非 NOT | ~ a | 反转被操作数的位。 |
左移 shift | a << b | 将 a 的二进制串向左移动 b 位,右边移入 0. |
算术右移 | a >> b | 把 a 的二进制表示向右移动 b 位,丢弃被移出的所有位。(译注:算术右移左边空出的位是根据最高位是 0 和 1 来进行填充的) |
无符号右移 (左边空出位用 0 填充) | a >>> b | 把 a 的二进制表示向右移动 b 位,丢弃被移出的所有位,并把左边空出的位都填充为 0 |
# 按位与(&)
每一位都为 1, 则为 1, 否则为 0.
const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011
console.log(a & b); // 00000000000000000000000000000001
// Expected output: 1
2
3
4
5
快捷记忆方式,可以将其记为 && ,当两边都为 true 时,结果为 true,否则为 false。
# 判断奇偶
将奇数转为二进制数以后, 最后一位必然为1. 因此任意奇数与 1 进行位与(&),结果均为 1.
num & 1 === 1 // 判断奇偶
# 判断系统权限
我们以二进制的 0001(1)、0010(2)、0100(4)、1000(8) 这类 2^n 数字作为权限标识,再用位与运算判断是否存在权限。
例如: 用户拥有 0001(1) + 0010(2) 权限。 即 0011。 我们在代码中就可以做以下判断。
const userRight = 3; // 0011
/**
* 是否拥有 1 权限。
* 3 - 0011
* 1 - 0001
* & - 0001
* 若结果 === 1 则为 true
*/
if (userRight === 1) {
doSomething...
}
/**
* 是否拥有 8 权限。
* 3 - 0011
* 8 - 1000
* & - 0000
* 若结果 === 8 则为 true
*/
if (userRight === 8) {
doSomething...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# lowbit
获取某字符最低的那个1的位置。
function lowbit(x) {
return x & -x;
}
2
3
原理解析:
lowbit( x ) = n & ( ~n + 1 ) = n & ( -n )
8 的二进制为 : 0 0 0 0 1 0 0 0
对 8 取反的二进制为 :1 1 1 1 0 1 1 1 (反码)
再对 取反8加一的二进制为 :1 1 1 1 1 0 0 0 (反码 + 1 = 补码)
进行与操作之后 : 0 0 0 0 1 0 0 0
就得到了我们的 lowbit ( 8 ) = 8
# 按位或(|)
若其中任一位为 1,则为 1。
const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011
console.log(a | b); // 00000000000000000000000000000111
// Expected output: 7
2
3
4
5
# 取整
将小数于 0 进行位或运算,结果将会进行取整。
/**
* 2.5 - 0010.1
* 0 - 0000
* | - 0010
*/
const a = 2.5; // 0010.1
console.log(a | 0); // 0010
// Expected output: 2
2
3
4
5
6
7
8
# 多选框
多选的原理和位于运算思想有些类似,我们可以取0001(1)、0010(2)、0100(4)、1000(8)标识选项。
若选中 1 + 2,则进行位或运算
1 | 2 = 3.
0001 | 0010 = 0011.
2
如果需要判断是否选中某个选项,则可以再采用位于运算, 判断是否选择 1 或 4.
3 & 1 = 1. // 选中
0011 & 0001 = 0001
3 & 4 = 0. // 未选中
0011 & 0100 = 0000
2
3
4
5
# 按位异或(^)
有且仅有一位是 1,才为 1。
const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011
console.log(a ^ b); // 00000000000000000000000000000110
// Expected output: 6
2
3
4
5
异或有几条性质,数学好点的可以尝试理解一下。
1、交换律
2、结合律 (a^b)^c == a^(b^c)
3、对于任何数x,都有 x^x=0,x^0=x
4、自反性: a^b^b=a^0=a;
2
3
4
# 数值交换
let a = 1;
let b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(a, b); // 2, 1
2
3
4
5
6
原理同下,下面是四则运算版本
let a = 1;
let b = 2;
a = a + b;
b = a - b;
a = a - b;
2
3
4
5
# 按位非(~)
取反操作
const a = 5; // 00000000000000000000000000000101
const b = -3; // 11111111111111111111111111111101
console.log(~a); // 11111111111111111111111111111010
// Expected output: -6
console.log(~b); // 00000000000000000000000000000010
// Expected output: 2
2
3
4
5
6
7
8
# 取整
原理同位或操作
~~(-5.88) // -5
# 左移(<<)、右移(>>)
左移,右移都是移动位数。如: 0010 << 1 = 0100, 0010 >> 1 = 0001
const a = 5; // 00000000000000000000000000000101
const b = 2; // 00000000000000000000000000000010
console.log(b >> 3); // 00000000000000000000000000010100
// Expected output: 20
2
3
4
5
const a = 5; // 00000000000000000000000000000101
const b = 2; // 00000000000000000000000000000010
const c = -5; // 11111111111111111111111111111011
console.log(a >> b); // 00000000000000000000000000000001
// Expected output: 1
console.log(c >> b); // 11111111111111111111111111111110
// Expected output: -2
2
3
4
5
6
7
8
9
# 扩大或缩小倍数并取整
左移、右移 需要记住的是每移动一位,影响了多少倍率,这个倍率是 2^n。 举例:
10 >> 1 = (10 / 2^1); // 5
2
注意: 这里的取整是舍去小数位,不是 Math.floor()
# 相关链接
MDN 表达式与运算符 - 位运算符 (opens new window)
js中的位运算及应用场景 (opens new window)
深入讲解js中的位运算及实际用法 (opens new window)