JavaScript 中的位操作符(Bitwise Operators)与典型应用场景
字数 1708 2025-12-11 03:41:00
JavaScript 中的位操作符(Bitwise Operators)与典型应用场景
在 JavaScript 中,位操作符用于直接操作数值的二进制位。虽然 JavaScript 的数字都是双精度浮点数,但进行位运算时,会先将操作数转换为 32 位有符号整数(补码表示),执行运算,然后再转换回 64 位浮点数。这个过程对开发者是透明的。
位操作符包括:
&(按位与 AND)|(按位或 OR)^(按位异或 XOR)~(按位非 NOT)<<(左移)>>(有符号右移)>>>(无符号右移)
理解这些操作符的关键在于明白它们对二进制位的操作逻辑。
1. 按位与(&)
原理:对两个操作数的每个对应位执行与操作,只有两个位都是 1 时,结果才为 1,否则为 0。
示例:
let a = 5; // 二进制:0101
let b = 3; // 二进制:0011
let result = a & b; // 二进制:0001 → 十进制 1
console.log(result); // 输出:1
典型应用:
- 判断奇偶性:
(n & 1) === 0表示 n 是偶数,(n & 1) === 1表示 n 是奇数。 - 权限控制:每个权限用一个二进制位表示,通过
&检查是否具有某个权限。 - 提取特定位:用掩码(mask)提取指定位。
2. 按位或(|)
原理:对两个操作数的每个对应位执行或操作,只要有一个位是 1,结果就为 1。
示例:
let a = 5; // 0101
let b = 3; // 0011
let result = a | b; // 0111 → 十进制 7
console.log(result); // 输出:7
典型应用:
- 组合权限:将多个权限合并到一个值中。
- 设置特定位为 1:使用掩码将指定位置 1。
3. 按位异或(^)
原理:对两个操作数的每个对应位执行异或操作,如果两个位不同,结果为 1;相同则为 0。
示例:
let a = 5; // 0101
let b = 3; // 0011
let result = a ^ b; // 0110 → 十进制 6
console.log(result); // 输出:6
典型应用:
- 交换两个变量的值(不用临时变量):
let x = 5, y = 3; x = x ^ y; y = x ^ y; x = x ^ y; console.log(x, y); // 输出:3, 5 - 简单的加密/解密:用同一个密钥异或两次可还原数据。
- 找出只出现一次的数字(在成对出现的数组中)。
4. 按位非(~)
原理:对操作数的每个位取反(0 变 1,1 变 0)。由于使用补码表示,~n 等于 -n - 1。
示例:
let a = 5; // 二进制:0000 0000 0000 0000 0000 0000 0000 0101
let result = ~a; // 取反:1111 1111 1111 1111 1111 1111 1111 1010 → 十进制 -6
console.log(result); // 输出:-6
典型应用:
- 快速取负减一:
~n等价于-n - 1。 - 结合
indexOf简化判断:if (~str.indexOf("search"))等价于if (str.indexOf("search") !== -1),因为indexOf返回 -1 时,~-1为 0(假值),其他情况为非零(真值)。
5. 左移(<<)
原理:将第一个操作数的所有位向左移动指定的位数,右侧空出的位补 0。左移 n 位相当于乘以 2^n。
示例:
let a = 5; // 二进制:0101
let result = a << 2; // 010100 → 十进制 20
console.log(result); // 输出:20 (5 * 2^2 = 20)
典型应用:
- 快速乘以 2 的幂:性能优于乘法(但现代 JavaScript 引擎的优化已不明显)。
- 组合多个值到一个整数:常用于颜色值、IP 地址的编码。
6. 有符号右移(>>)
原理:将第一个操作数的所有位向右移动指定的位数,左侧空出的位用符号位(最高位)填充。右移 n 位相当于除以 2^n 并向下取整。
示例:
let a = -20; // 二进制补码表示:1111 1111 1111 1111 1111 1111 1110 1100
let result = a >> 2; // 右移两位:1111 1111 1111 1111 1111 1111 1111 1011 → 十进制 -5
console.log(result); // 输出:-5(-20 / 4 = -5)
典型应用:
- 快速除以 2 的幂(向下取整):对于正数和负数都适用。
7. 无符号右移(>>>)
原理:将第一个操作数的所有位向右移动指定的位数,左侧空出的位补 0。对于正数,结果与 >> 相同;对于负数,结果会变成很大的正数。
示例:
let a = -20; // 二进制补码:1111 1111 1111 1111 1111 1111 1110 1100
let result = a >>> 2; // 右移两位:0011 1111 1111 1111 1111 1111 1111 1011 → 十进制 1073741819
console.log(result); // 输出:1073741819
典型应用:
- 将负数转换为正数(但值会变化):通常用于处理二进制数据或颜色值,确保结果为非负整数。
典型应用场景实例
场景 1:权限控制
假设有三种权限:读(1 << 0)、写(1 << 1)、执行(1 << 2)。
const READ = 1 << 0; // 1
const WRITE = 1 << 1; // 2
const EXECUTE = 1 << 2;// 4
let userPermissions = 0;
// 授予读和写权限
userPermissions = userPermissions | READ | WRITE; // 3 (二进制 011)
// 检查是否有写权限
if (userPermissions & WRITE) {
console.log("有写权限");
}
// 移除读权限
userPermissions = userPermissions & ~READ;
场景 2:颜色值处理(ARGB)
颜色值通常表示为 32 位整数,每 8 位表示一个通道(Alpha, Red, Green, Blue)。
function getAlpha(color) {
return (color >>> 24) & 0xFF;
}
function getRed(color) {
return (color >>> 16) & 0xFF;
}
// 设置绿色分量
function setGreen(color, green) {
return (color & ~(0xFF << 8)) | ((green & 0xFF) << 8);
}
let color = 0xFF336699; // ARGB
console.log(getAlpha(color).toString(16)); // 输出:ff
场景 3:快速判断是否为 2 的幂
function isPowerOfTwo(n) {
return n > 0 && (n & (n - 1)) === 0;
}
// 原理:2 的幂的二进制表示只有一个 1,n-1 会将该位变为 0,低位全变为 1,按位与结果为 0。
注意事项
- 32 位限制:位运算只作用于 32 位整数,超出范围的位会被截断。
- 性能考量:在现代 JavaScript 引擎中,位运算的性能优势已经不明显,除非在密集计算的场景(如图像处理、游戏)。可读性和正确性应优先。
- 负数的处理:注意有符号右移和无符号右移的区别,尤其是在处理二进制数据时。
通过理解位操作符的原理和典型应用,你可以在需要底层操作或优化时,更有效地使用它们。