JS中的位运算

612 阅读6分钟

JS中的位运算

  • 所有 JavaScript 数字存储为根为 10 的 64(8比特)浮点数。JavaScript 不是类型语言。与许多其他编程语言不同,JavaScript 不定义不同类型的数字,比如整数、短、长、浮点等等。
  • 整数精度(不使用小数点或指数计数法)最多为 15 位。小数精度的最大位数是17,但是浮点运算并不总是 100% 准确。
  • 位运算直接对二进制位进行计算,位运算直接处理每一个比特位,是非常底层的运算,好处是速度极快,缺点是很不直观,许多场合不能够使用。
  • 位运算只对整数起作用,如果一个运算数不是整数,会自动转为整数后再运行。 在 JavaScript 内部,数值都是以 64 位浮点数的形式储存,但是做位运算的时候,是以 32 位带符号的整数进行运算的,并且返回值也是一个32 位带符号的整数。

位运算符用于直接对二进制位进行计算,一共有7个。

  • 二进制或运算符(or):符号为|,表示若两个二进制位都为0,则结果为0,否则为1。
  • 二进制与运算符(and):符号为&,表示若两个二进制位都为1,则结果为1,否则为0。
  • 二进制否运算符(not):符号为~,表示对一个二进制位取反。
  • 异或运算符(xor):符号为^,表示若两个二进制位不相同,则结果为1,否则为0。
  • 左移运算符(left shift):符号为<<
  • 右移运算符(right shift):符号为>>
  • 带符号位的右移运算符(zero filled right shift):符号为>>>

JS 中的 7 个位元素符。

1. 按位与(and) &

& 以特定的方式组合操作二进制数中对应的位,如果对应的位都为1,那么结果就是1, 如果任意一个位是0 则结果就是0。

// 1的二进制表示为: 00000000 00000000 00000000 00000001
// 3的二进制表示为: 00000000 00000000 00000000 00000011
// -----------------------------
// 1的二进制表示为: 00000000 00000000 00000000 00000001
console.log(1 & 3)     // 1

2.按位或(OR) |

| 运算符跟 & 的区别在于如果对应的位中任一个操作数为 1 那么结果就是 1。

// 1的二进制表示为: 00000000 00000000 00000000 00000001
// 3的二进制表示为: 00000000 00000000 00000000 00000011
// -----------------------------
// 3的二进制表示为: 00000000 00000000 00000000 00000011
console.log(1 | 3)     // 3

3.按位异或(xor) ^

^ 如果对应两个操作位有且仅有一个 1 时结果为 1,其他都是 0。

// 1的二进制表示为: 00000000 00000000 00000000 00000001
// 3的二进制表示为: 00000000 00000000 00000000 00000011
// -----------------------------
// 2的二进制表示为: 00000000 00000000 00000000 00000010
console.log(1 ^ 3)     // 2

4.按位非(not) ~

~ 运算符是对位求反,1变0, 0变1,也就是求二进制的反码。

// 1的二进制表示为: 00000000 00000000 00000000 00000001
// 3的二进制表示为: 00000000 00000000 00000000 00000011
// -----------------------------
// 1反码二进制表示: 11111111 11111111 11111111 11111110
// 由于第一位(符号位)是1,所以这个数是一个负数。JavaScript 内部采用补码形式表示负数,即需要将这个数减去1,再取一次反,然后加上负号,才能得到这个负数对应的10进制值。
// -----------------------------
// 1的反码减1:     11111111 11111111 11111111 11111101
// 反码取反:       00000000 00000000 00000000 00000010
// 表示为10进制加负号:-2
console.log(~ 1)     // -2

一个数与自身的取反值相加等于-1。

5.左移(left shift)

<< 运算符使指定值的二进制数所有位都左移指定次数,其移动规则:丢弃高位,低位补0即按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零

// 1的二进制表示为: 00000000 00000000 00000000 00000001
// -----------------------------
// 2的二进制表示为: 00000000 00000000 00000000 00000010
console.log(1 << 1)     // 2

6.有符号右移 >>

>> 该操作符会将指定操作数的二进制位向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。

// 1的二进制表示为: 00000000 00000000 00000000 00000001
// -----------------------------
// 0的二进制表示为: 00000000 00000000 00000000 00000000
console.log(1 >> 1)     // 0

7.无符号右移 >>>

>>> 该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充。因为符号位变成了 0,所以结果总是非负的。(译注:即便右移 0 个比特,结果也是非负的。)

对于非负数,有符号右移和无符号右移总是返回相同的结果。例如, 9 >>> 2 得到 2 和 9 >> 2 相同。