JavaScript 位运算的 20 种实用技巧与底层实现

作者:霁月

时间:2026-11-01

浏览:499

本文深入解析 JavaScript 中位运算的 20 种高级用法,涵盖乘除加速、奇偶判断、变量交换、绝对值计算及汉明权重等场景。通过具体代码示例,展示如何利用位移、掩码和异或等操作实现无分支逻辑、布尔数组压缩及颜色混合,帮助开发者理解底层机制并提升代码执行效率。

文章目录

位运算在 JavaScript 开发中常被忽视,但其在底层性能优化和特定算法实现中具有独特价值。掌握这些技巧有助于编写更紧凑、高效的代码。

1. 乘法和除法运算

利用位移操作可以高效实现整数的乘 2 或除 2 运算。例如,num << 1 表示将数值左移一位实现乘 2,而 num >> 1 则表示右移一位实现除 2。这种操作比标准的乘除法运算符更快,因为位移直接对应硬件层面的二进制移动。

let num = 4;
let multiplied = num << 1; // 结果为8
let divided = num >> 1; // 结果为2

2. 判断奇偶性

判断一个整数是奇数还是偶数,可以通过将其与 1 进行按位与(&)运算来实现。如果结果非零,则该数为奇数;否则为偶数。这种方法避免了取模运算的开销,直接检查最低位即可得出结论。

let num = 7;
let isOdd = num & 1; // 结果为1,奇数

3. 交换变量

利用异或(^)运算的特性,可以在不使用临时变量的情况下交换两个整数的值。通过三次异或操作,分别对两个变量进行异或处理,即可实现值的互换,这在内存受限的环境中尤为有用。

let a = 2, b = 3;
a ^= b;
b ^= a;
a ^= b; // a === 3, b === 2

4. 取绝对值

通过位运算获取整数的绝对值,可以利用符号位进行计算。具体做法是将数值与其算术右移 31 位的结果进行异或,再减去该右移结果。这种方法避免了条件分支判断,提高了执行速度。

let num = -6;
let abs = (num ^ (num >> 31)) - (num >> 31); // 结果为6

5. 检测数值是否为2的幂

判断一个数是否为 2 的幂,可以通过检查其二进制表示中是否仅包含一个 1 来实现。具体做法是将该数与自身减 1 的结果进行按位与运算,若结果为 0,则说明原数是 2 的幂。

let num = 8;
let isPowerOfTwo = (num & (num - 1)) === 0; // 结果为true

6. 轮转位

位轮转(Rotate)操作允许将二进制位进行循环移动,分为左轮转和右轮转。例如,右轮转 3 位可以通过将数值右移 3 位后,与左移 (32-3) 位的结果进行按位或运算来实现,从而保留被移出的位。

let num = 21; // (10101)
num = (num >> 3) | (num << (32 - 3)); // 右轮转3位

7. 快速计算

某些特定的数学计算可以通过位运算加速。例如,计算 n 的 2 倍可以通过 n << n 实现,即左移 n 位。这种技巧在需要快速倍增数值的场景中非常有效。

let n = 5;
let result = 5 << 5; // 结果为160

8. 掩码运算

掩码(Mask)是位运算中的核心概念,用于提取或修改二进制数据的特定部分。通过定义特定的掩码值,可以快速从复合数据中提取出所需的字段信息,常用于处理颜色值或协议数据。

// 使用掩码获取RGB颜色的红色分量
let color = 0xffeEDC;
let red = (color & 0xff0000) >> 16;

9. 快速翻转运算

利用异或运算可以实现特定位的翻转(Flip),而不影响其他位。通过定义一个包含需要翻转位的掩码,与原数值进行异或操作,即可实现“不改变其他位的情况下翻转特定位”的功能。

let flags = 5; // (101)
let mask = 2; // (010)
flags ^= mask; // 结果为7 (111)

10. 利用掩码来设置位

使用按位或(|)运算和掩码,可以将特定位置为 1,同时保持其他位不变。例如,将数值与 2 进行或运算,即可确保第 1 位(从0开始计数)被设置为 1。

let num = 4; // (100)
num |= 2; // 结果为6 (110)

11. 利用掩码来清零位

通过按位与(&)运算和取反掩码,可以将特定位置为 0。例如,将数值与 ~8 进行与运算,即可清除第 3 位,而其他位保持不变。

let num = 15; // (1111)
num &= ~8; // 结果为7 (0111)

12. 低效的按位非运算

按位非(~)运算会将所有位取反。对于整数而言,~num 的结果等价于 -num - 1。因此,可以通过 ~num 来实现变量值减 1 的操作,尽管这在现代 JavaScript 引擎中可能并不比直接减法更高效。

let num = 10;
num = ~num; // 结果为-11

13. 条件无分支

位运算可以实现无分支的条件判断,适用于对性能极度敏感的场景。通过算术右移和按位与操作,可以替代 if-else 语句,避免分支预测失败带来的性能损耗。

let a = 10, b = 20;
let max = a - ((a - b) & ((a - b) >> 31));

14. 检测位是否被置位

检测某一位是否为 1,可以通过将该位对应的掩码与原数值进行按位与运算来实现。如果结果非零,则说明该位被置位;否则为 0。

let flag = 8; // (1000)
let isSet = flag & (1 << 3); // 结果为8,表示第3位被置位

15. 浮点数转整数

利用零填充右移(>>>)操作,可以将浮点数转换为整数。具体做法是将浮点数右移 0 位,这会丢弃小数部分并向下取整,实现快速截断。

let floatNum = 3.9;
let intNum = floatNum >> 0; // 结果为3

16. RGB颜色混合

利用位运算完成RGB颜色值的混合处理。

let color1 = 0xff00ff, color2 = 0x00ff00;
let mixed = (color1 & color2) + (((color1 ^ color2) & 0xfefefe) >> 1);

17. 模2^n取余

当一个数是 2 的幂时,取模运算可以通过位与操作加速。例如,num & (8 - 1) 等价于 num % 8。这种技巧在哈希表实现或缓冲区管理中非常常见。

let num = 19;
let mod = num & (8 - 1); // 结果为3,相当于19 % 8

18. 实现布尔数组

使用位运算可以高效实现布尔数组,从而节省内存空间。通过将多个布尔值压缩到一个整数中,利用位移和掩码操作来设置或检测特定索引位的值,适用于大规模数据标记场景。

let array = 0;
array |= 1 << index; // 设置index位置为1
let isTrue = (array & (1 << index)) !== 0; // 检测index位置是否为1

19. 求相反数

通过位运算获取一个数的相反数,可以利用补码的性质。具体做法是对数值进行按位非运算后加 1,即 ~num + 1,即可得到其相反数。

let num = -48;
let opposite = ~num + 1; // 结果为48

20.计算汉明权重

汉明权重(Hamming Weight)是指一个数二进制表示中 1 的个数。通过循环执行 num &= (num - 1) 操作,每次清除最低位的 1,直到数值为 0,统计循环次数即可得到汉明权重。

let num = 13; // (1101)
let count = 0;
while(num) {
    count++;
    num &= num - 1; // 清除最低位的1
}
// 结果 count 为3

以上就是 20 个 JavaScript 位运算用法的详细内容,更多关于 js 位运算用法的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章