前端-JavaScript位运算

243 阅读4分钟

一、什么是位运算

  JavaScript 中的位运算符允许直接对二进制位进行操作,这是在底层操作数据的一种非常高效的方式。尽管在现代 JavaScript 开发中,位运算可能不是非常常见,但在某些特定场景(如算法优化、低层级数据处理、加密等)中仍然非常有用。

二、常用位运算

1. 按位与 (&)

  • 运算规则: 按位与运算符将两个数的每一位进行 AND 运算,只有在两个对应的二进制位都为 1 时,结果才为 1,否则为 0

  • 特点

    • 任何数与 0 进行按位与,结果为 0a & 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 进行按位或,结果总是 1a | 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

    • 任何数与自己进行异或,结果为 0a ^ a = 0

let a = 5;  // 二进制: 0101
let b = 3;  // 二进制: 0011
console.log(a ^ b);  // 结果: 6 (二进制: 0110)

4. 按位非 (~)

  • 运算规则:按位非运算符对一个数的每一位进行取反操作,即 0110。它等同于 -n-1

  • 特点

    • 任何数按位取反,结果是该数的负数减 1:~a = -(a+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^na << 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)