JavaScript 二进制与位运算底层原理及实战技巧

咖啡半糖
咖啡半糖
发布时间:2026-10-15 | 6人浏览过
原创

JavaScript 的位运算基于 32 位有符号整数执行,理解原码、反码、补码的转换及 32 位溢出机制是掌握位运算技巧的关键。本文详解各 bitwise 运算符的行为逻辑,包括利用异或实现变量交换、通过状态位组合管理多条件等实用场景。

1. 预备知识:32 位有符号整数与补码

在 JavaScript 中,所有数值类型均为双精度浮点数(64位),但进行位运算时,操作数会首先被转换为 int32(32位有符号整数)。这意味着位运算仅影响低 32 位,且最高位被视为符号位(0为正,1为负)。

第1步:理解整数的表达范围

由于是 32 位有符号整数,其取值范围为:

-Math.pow(2,31) ~ Math.pow(2,31)-1 // -2147483648 ~ 2147483647

第2步:掌握原码、反码与补码

计算机内部使用补码进行加减运算,以统一正负数的处理逻辑。

  • 原码:最高位为符号位,其余位表示数值绝对值。
  • 反码:正数反码同原码;负数反码为原码符号位不变,其余位按位取反。
  • 补码:正数补码同原码;负数补码为反码加 1。

关键点:+0 和 -0 的补码相同,均为全 0。对于负数 $-M$,其补码等价于正数 $2^{32} - M$。这种设计使得减法可以转化为加法(例如 $A - B$ 变为 $A + (-B)$ 的补码),利用模 $2^{32}$ 的溢出特性自然丢弃高位进位。

第3步:验证补码原理(以 -3 为例)

负数 -3 的计算过程如下:

  1. 原码(3的二进制取反并加符号位):1000...0011
  2. 反码(符号位不变,数值位取反):1111...1100
  3. 补码(反码 + 1):1111...1101

此时,补码与原码相加: (1111...1101) + (1000...0011) = 1 0000...0000 结果为 $2^{32}$,即 32 位溢出归零,符合数学逻辑。

2. 核心位运算符详解

位运算仅对整数有效。若操作数为非整数,JS 引擎会将其向下取整(如 ~NaN 等同于 ~0,结果为 -1)。

第4步:按位取反 (~)

一元运算符,将每一位 0 变 1,1 变 0。由于涉及符号位,结果通常为负数。公式可近似理解为:~x === -(x + 1)。

~123; // -124

第5步:按位与 (&) 和 按位或 (|)

  • &:两位均为 1 则结果为 1,否则为 0。常用于掩码操作(如 x & 1 判断奇偶)。
  • |:有一位为 1 则结果为 1。常用于合并状态标志。

示例:

234 & 234; // 234
234 | 234; // 234
// 更典型的例子:
"00000000000000000000000001111011" // 234
"00000000000000000000000011101010" // 234 对应的另一个数
---------------------------------------------
"00000000000000000000000001101010" // 与的结果

第6步:按位异或 (^)

两位不同则为 1,相同则为 0。异或运算具有以下重要性质:

  • 自反性:a ^ a = 0
  • 结合律:(a ^ b) ^ c = a ^ (b ^ c)
  • 交换律:a ^ b = b ^ a
  • 恒等性:a ^ 0 = a

3. 实战应用技巧

第7步:利用异或交换两个变量

无需临时变量即可交换两个整数的值,这是面试中常见的位运算技巧:

a = a ^ b;
b = a ^ b; // b = (a^b)^b = a
a = a ^ b; // a = (a^b)^a = b

第8步:利用状态位记录多重信息

当需要记录多个布尔状态(如权限、标志位)时,可使用 | 将状态值合并到一个整数中,利用异或或位与进行查询或移除。前提是各个状态值必须是 $2^n$ 的形式(即二进制只有一位为 1)。

例如定义状态常量:

const READ = 1;   // 0001
const WRITE = 2;  // 0010
const EXECUTE = 4; // 0100
const DELETE = 8;  // 1000

组合权限:

let permissions = READ | WRITE | EXECUTE; // 值为 7 (0111)
// 检查是否拥有 WRITE 权限
if (permissions & WRITE) {
  console.log("拥有写入权限");
}

第9步:位移运算优化乘除

  • 左移 (<<):低位补 0,相当于乘以 $2^n$。注意不要超过 31 位,否则可能改变符号位或导致未预期结果。
  • 右移 (>>):有符号右移,高位补符号位,相当于带符号除以 $2^n$ 并向下取整。
  • 无符号右移 (>>>):高位补 0,将操作数视为无符号整数。这对于处理负数转无符号大整数非常有用。

示例:

-123 >>> 1; // 2147483586 (负数转为巨大的正数)

4. 注意事项与边界情况

在执行位运算时,需特别注意以下细节以避免逻辑错误:

  1. 强制类型转换:非整数操作数会被截断为整数部分。字符串、对象等非数字类型通常会被转为 0 或 NaN(进一步转为 0)。
  2. 移位次数取模:移位操作符右侧的操作数会对 32 取模。例如 1 << 32 等同于 1 << 0,结果仍为 1,而非预期中的 0 或溢出。
  3. 超大整数溢出风险:虽然 JS 数字精度高达 64 位,但位运算只保留低 32 位。如果一个大于 Math.pow(2,31)-1 的正数参与位运算,其第 32 位(符号位)若为 1,结果将被解释为负数。

以上就是 JavaScript 二进制与位运算底层原理及实战技巧的详细内容,更多关于 JavaScript 高级编程的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表