JavaScript位运算应用场景

前端3 min
#JavaScript
目录(16)

位运算

OperatorUsageDescription
按位与 ANDa & b在 a,b 的位表示中,每一个对应的位都为 1 则返回 1,否则返回 0.
按位或 ORa | b在 a,b 的位表示中,每一个对应的位,只要有一个为 1 则返回 1,否则返回 0.
按位异或 XORa ^ b在 a,b 的位表示中,每一个对应的位,两个不相同则返回 1,相同则返回 0.
按位非 NOT~ a反转被操作数的位。
左移 shifta << 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

快捷记忆方式,可以将其记为 && ,当两边都为 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...
}

lowbit

获取某字符最低的那个1的位置。

function lowbit(x) {
  return x & -x;
}

原理解析:

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 的个数

let count = 0;
while(x > =){
  x &= x - 1;
  count++;
}

按位或(|)

若其中任一位为 1,则为 1。

const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011

console.log(a | b); // 00000000000000000000000000000111
// Expected output: 7

取整

将小数于 0 进行位或运算,结果将会进行取整。

/**
 * 2.5 - 0010.1
 * 0   - 0000
 * |   - 0010
 */
const a = 2.5; // 0010.1
console.log(a | 0); // 0010
// Expected output: 2

多选框

多选的原理和位于运算思想有些类似,我们可以取0001(1)、0010(2)、0100(4)、1000(8)标识选项。

若选中 1 + 2,则进行位或运算

1 | 2 = 3. 
0001 | 0010 = 0011.

如果需要判断是否选中某个选项,则可以再采用位于运算, 判断是否选择 1 或 4.

3 & 1 = 1. // 选中
0011 & 0001 = 0001

3 & 4 = 0. // 未选中
0011 & 0100 = 0000

按位异或(^)

有且仅有一位是 1,才为 1。

const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011

console.log(a ^ b); // 00000000000000000000000000000110
// Expected output: 6

异或有几条性质,数学好点的可以尝试理解一下。

1、交换律
2、结合律 (a^b)^c == a^(b^c)
3、对于任何数x,都有 x^x=0,x^0=x
4、自反性: a^b^b=a^0=a;

数值交换

let a = 1;
let b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(a, b); // 2, 1

原理同下,下面是四则运算版本

let a = 1;
let b = 2;
a = a + b;
b = a - b;
a = a - b;

按位非(~)

取反操作

const a = 5; // 00000000000000000000000000000101
const b = -3; // 11111111111111111111111111111101

console.log(~a); // 11111111111111111111111111111010
// Expected output: -6

console.log(~b); // 00000000000000000000000000000010
// Expected output: 2

取整

原理同位或操作

~~(-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
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^n。 举例:

10 >> 1 = (10 / 2^1); // 5

注意: 这里的取整是舍去小数位,不是 Math.floor()

相关链接

MDN 表达式与运算符 - 位运算符

js中的位运算及应用场景

深入讲解js中的位运算及实际用法

位运算(&、|、^、~、>>、<<)

【位运算】深入理解并证明 lowbit 运算