js 的按位操作符

417 阅读6分钟

按位操作符(Bitwise operators) 将其操作数(operands)当作32位的比特序列(由0和1组成),而不是十进制、十六进制或八进制数值。例如,十进制数9,用二进制表示则为1001。按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值

操作数被转换成 32 位整数,用比特序列(0 和 1 组成)表示。超过 32 位的数字会被丢弃

68719476733 的二进制序列: 1111 11111111 11111111 11111111 11111101

68719476733 << 0 = -3

-3 的二进制序列 11111111 11111111 11111111 11111101

运算符用法描述
按位与( AND)a & b对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
按位或(OR)`ab`对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。
按位异或(XOR)a ^ b对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
按位非(NOT)~ a反转操作数的比特位,即0变成1,1变成0。
左移(Left shift)a << ba 的二进制形式向左移 b (< 32) 比特位,右边用0填充。
有符号右移a >> b将 a 的二进制表示向右移b(< 32) 位,丢弃被移出的位。
无符号右移a >>> b将 a 的二进制表示向右移b(< 32) 位,丢弃被移出的位,并使用 0 在左侧填充。
  1. & 按位与(and)

    // 1的二进制表示为: 00000000 00000000 00000000 00000001
    // 3的二进制表示为: 00000000 00000000 00000000 00000011
    // -----------------------------
    // 1 & 3 的结果: 00000000 00000000 00000000 00000001
    // 10进制表示为: 1
    console.log(1 & 3)     // 1
    
    // 3的二进制表示为: 00000000 00000000 00000000 00000011
    // 5的二进制表示为: 00000000 00000000 00000000 00000101
    // -----------------------------
    // 3 & 5 的结果: 00000000 00000000 00000000 00000001
    // 10进制表示为: 1
    console.log(3 & 5)     // 1
    
    // 2的二进制表示为: 00000000 00000000 00000000 00000010
    // 4的二进制表示为: 00000000 00000000 00000000 00000100
    // -----------------------------
    // 2 & 4 的结果: 00000000 00000000 00000000 00000000
    // 10进制表示为: 0
    console.log(2 & 4)     // 0
    
  2. | 按位或(or)

    // 1的二进制表示为: 00000000 00000000 00000000 00000001
    // 3的二进制表示为: 00000000 00000000 00000000 00000011
    // -----------------------------
    // 1 | 3 的结果: 00000000 00000000 00000000 00000011
    // 10进制表示为: 3
    console.log(1 & 3)     // 3
    
    // 3的二进制表示为: 00000000 00000000 00000000 00000011
    // 5的二进制表示为: 00000000 00000000 00000000 00000101
    // -----------------------------
    // 3 | 5 的结果: 00000000 00000000 00000000 00000111
    // 10进制表示为: 7
    console.log(3 | 7)     // 7
    
    // 2的二进制表示为: 00000000 00000000 00000000 00000010
    // 4的二进制表示为: 00000000 00000000 00000000 00000100
    // -----------------------------
    // 2 | 4 的结果: 00000000 00000000 00000000 00000110
    // 10进制表示为: 6
    console.log(2 | 4)     // 6
    
  3. ^按位异或(xor)

    // 1的二进制表示为: 00000000 00000000 00000000 00000001
    // 3的二进制表示为: 00000000 00000000 00000000 00000011
    // -----------------------------
    // 1 ^ 3 的结果: 00000000 00000000 00000000 00000010
    // 10进制表示为: 2
    console.log(1 ^ 3)     // 2
    
    // 3的二进制表示为: 00000000 00000000 00000000 00000011
    // 5的二进制表示为: 00000000 00000000 00000000 00000101
    // -----------------------------
    // 3 ^ 5 的结果: 00000000 00000000 00000000 00000110
    // 10进制表示为: 6
    console.log(3 ^ 7)     // 6
    
    // 2的二进制表示为: 00000000 00000000 00000000 00000010
    // 4的二进制表示为: 00000000 00000000 00000000 00000100
    // -----------------------------
    // 2 ^ 4 的结果: 00000000 00000000 00000000 00000110
    // 10进制表示为: 6
    console.log(2 ^ 4)     // 6
    
  4. ~按位非(not)

    高位舍弃,低位补0

    // 由于第一位(符号位)是1,所以这个数是一个负数。JavaScript 内部采用补码形式表示负数,即需要将这个数减去1,再取一次反,然后加上负号,才能得到这个负数对应的10进制值。
    // 1的二进制表示为: 00000000 00000000 00000000 00000001
    // 1反码二进制表示: 11111111 11111111 11111111 11111110
    // 1的反码减1:     11111111 11111111 11111111 11111101
    // 反码取反:       00000000 00000000 00000000 00000010
    // 表示为10进制加负号:-2
    console.log(~ 1)     // -2
    
    // 3的二进制表示为: 00000000 00000000 00000000 00000011
    // 3反码二进制表示为: 11111111 11111111 11111111 11111100
    // 3反码减1: 11111111 11111111 11111111 11111011
    // 3反码减取反: 00000000 00000000 00000000 00000100
    // 3反码表示为10进制: -4
    console.log(~ 3)     // -4
    
    
  5. << 左移(left shift) 将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充

    由第一个操作数向左移动,因此保留称号位

    // 1的二进制表示为: 00000000 00000000 00000000 00000001
    // 1 << 3: 00000000 00000000 00000000 00001000
    // 10进制表示为: 8
    console.log(1 << 3)     // 8
    
    // -1的二进制表示为: 11111111 11111111 11111111 11111111
    // -1 << 1: 11111111 11111111 11111111 11111110
    console.log(-1 << 1); // -2
    
    // 9的二进制表示为: 00000000 00000000 00000000 00001001
    // 9 << 2: 00000000 00000000 00000000 00100100
    9 << 2; // 36
    
    // -9的二进制表示为: 11111111 11111111 11111111 11110111
    // -9 << 2: 11111111 11111111 11111111 11011100
    -9 << 2; // -36
    
  6. >>有符号右移(right shift)该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。

    // 9的二进制表示为: 00000000 00000000 00000000 00001001
    // 9 >> 2: 00000000 00000000 00000000 00000010
    9 >> 2; // 2
    
    // -9的二进制表示为: 11111111 11111111 11111111 11110111
    // -9 >> 2: 11111111 11111111 11111111 11111101
    -9 >> 2; // -3
    
  7. >>>无符号右移(unsigned right shift)该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充。因为符号位变成了 0,所以结果总是非负的。(译注:即便右移 0 个比特,结果也是非负的。)

    对于正数,>> >>> 结果相同

    对于结果,当成是无符号的二进制序列来转

    // 9的二进制表示为: 00000000 00000000 00000000 00001001
    // 9 >>> 2: 00000000 00000000 00000000 00000010
    9 >> 2; // 2
    00000111
    // -9的二进制表示为: 11111111 11111111 11111111 11110111
    // -9 >>> 2: 00111111 11111111 11111111 11111101
    -9 >>> 2; // 1073741821
    // -9 >>> 1: 11111111 11111111 11111111 11110111
    // 将结果当成无符号二进制序列处理,即为: 2^32 - 1  - 2^3 = 4294967287
    -9 >>> 0; // 4294967287
    // -1073741833的二进制表示为: 10111111 11111111 11111111 11110111
    // -1073741833 >>> 0: 10111111 11111111 11111111 11110111
    // 将结果当成无符号二进制序列处理,即为: 2^32 - 1 - 2^30 - 2^3 = 3221225463
    -1073741833 >>> 0; // 3221225463
    

应用

  1. 判断奇偶

    // 奇数则二进制末位为1
    // 奇数 & 1 = 0
    // 偶数 & 1 = 1
    2 & 1; // 0
    5 & 1; // 1