一、什么是位运算
JavaScript 中的位运算符允许直接对二进制位进行操作,这是在底层操作数据的一种非常高效的方式。尽管在现代 JavaScript 开发中,位运算可能不是非常常见,但在某些特定场景(如算法优化、低层级数据处理、加密等)中仍然非常有用。
二、常用位运算
1. 按位与 (&)
-
运算规则: 按位与运算符将两个数的每一位进行
AND运算,只有在两个对应的二进制位都为1时,结果才为1,否则为0。 -
特点:
-
任何数与
0进行按位与,结果为0:a & 0 = 0 -
任何数与
1进行按位与,结果为该数的最低位:a & 1 = a的最低位(如果a为偶数,结果为0;如果a为奇数,结果为1)
-
let a = 5; // 二进制: 0101
let b = 3; // 二进制: 0011
console.log(a & b); // 结果: 1 (二进制: 0001)
2. 按位或 (|)
-
运算规则:按位或运算符将两个数的每一位进行
OR运算,只要对应的二进制位中有一个为1,结果就是1,否则为0。 -
特点:
-
任何数与
0进行按位或,结果为该数本身:a | 0 = a。 -
任何数与
1进行按位或,结果总是1:a | 1 = 1(如果a为奇数,结果为1;如果a为偶数,结果为a+1)。
-
let a = 5; // 二进制: 0101
let b = 3; // 二进制: 0011
console.log(a | b); // 结果: 7 (二进制: 0111)
3. 按位异或 (^)
-
运算规则:按位异或运算符将两个数的每一位进行
XOR运算,当对应的二进制位不同(一个为0,另一个为1)时,结果为1,否则为0。 -
特点:
-
任何数与
0进行异或,结果为该数本身:a ^ 0 = a。 -
任何数与自己进行异或,结果为
0:a ^ a = 0。
-
let a = 5; // 二进制: 0101
let b = 3; // 二进制: 0011
console.log(a ^ b); // 结果: 6 (二进制: 0110)
4. 按位非 (~)
-
运算规则:按位非运算符对一个数的每一位进行取反操作,即
0变1,1变0。它等同于-n-1。 -
特点:
- 任何数按位取反,结果是该数的负数减 1:
~a = -(a+1)。
- 任何数按位取反,结果是该数的负数减 1:
let a = 5; // 5 的二进制表示为:00000000 00000000 00000000 00000101
let result = ~a; // 按位取反后为: 11111111 11111111 11111111 11111010
console.log(result); // 输出: -6
5. 左移 (<<)
-
运算规则:左移运算符将一个数的二进制位向左移动指定的位数,右侧用
0填充。左移一位相当于乘以2。 -
特点:
-
左移
n位相当于乘以2^n:a << n = a * 2^n。 -
容易造成溢出:移位过多可能导致超出数值表示范围,造成数据丢失。
-
let a = 5; // 二进制: 0101
console.log(a << 1); // 结果: 10 (二进制: 1010)
6. 右移 (>>)
-
运算规则:右移运算符将一个数的二进制位向右移动指定的位数,左侧用符号位(即最高位的值,0或1)填充。如果是正数,左侧填充
0,如果是负数,左侧填充1。右移一位相当于除以2。 -
特点:
-
右移
n位相当于除以2^n,向下取整:a >> n = Math.floor(a / 2^n)。 -
保持符号位不变:负数右移时,符号位
1保持不变。
-
let a = 5; // 二进制: 0101
console.log(a >> 1); // 结果: 2 (二进制: 0010)
let b = -5; // 二进制: 11111111111111111111111111111011 (32位)
console.log(b >> 1); // 结果: -3 (二进制: 11111111111111111111111111111101)
7. 无符号右移 (>>>)
-
运算规则:无符号右移运算符将一个数的二进制位向右移动指定的位数,左侧总是用
0填充,不管符号位是什么。无符号右移对于正数和右移效果相同,但对于负数,结果会变成非常大的正数。 -
特点:
-
无符号右移忽略符号位,左侧总是补
0。 -
对于正数和右移效果相同:
a >>> n = Math.floor(a / 2^n)。 -
负数无符号右移后会变成一个非常大的正数,因为左侧补
0,导致符号位被重置。
-
let a = 5; // 二进制: 0101
console.log(a >>> 1); // 结果: 2 (二进制: 0010)
let b = -5; // 二进制: 11111111111111111111111111111011 (32位)
console.log(b >>> 1); // 结果: 2147483645 (二进制: 01111111111111111111111111111101)