js的位运算

499 阅读5分钟

位运算符用于直接对二进制位进行计算,一共有7个。运算符直接处理每一个比特位(bit),所以是非常底层的运算,好处是速度极快,缺点是很不直观,许多场合不能使用它们,否则会使代码难以理解和查错。

位运算符只对整数起作用,如果一个运算子不是整数,会自动转为整数后再执行。另外,虽然在 JavaScript 内部,数值都是以64位浮点数的形式储存,但是做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数。

在计算机内,有符号数有3种表示法:原码、反码和补码。

所谓原码就是二进制定点表示法,即最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。

反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。

补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。

注: 位运算时,是先转为补码再进行运算的。

按位与&

&&运算符我们都知道,只有两个都为真,结果才为真。&道理是一样的,同位都为1,才返回1。例如1和3的按位与操作, 1 & 3 = 1 。

    00000000 00000000 00000000 00000001
    00000000 00000000 00000000 00000011
&   -----------------------------------
    00000000 00000000 00000000 00000001

通常我们判断一个数字是奇数还是偶数,我们会通过取余

function assert(n) {
    if (n % 2 === 1) {
        console.log("n是奇数");
    } else {
        console.log("n是偶数");
   }
}

assert(3); // "n是奇数"

我们也可以用一个数和1进行按位&操作来判断,而且速度更快:

function assert(n) {
    if (n & 1) {
        console.log("n是奇数");
    } else {
        console.log("n是偶数");
    }
}

assert(3); // "n是奇数"

按位或|

||运算符我们都知道,只要有个一个为真,结果就为真。|的道理也是一样的,同位都一个为1,就返回1。例如1和3的按位或操作, 1 | 3 = 3 。

    00000000 00000000 00000000 00000001
    00000000 00000000 00000000 00000011
|   -----------------------------------
    00000000 00000000 00000000 00000011

按位非~

按位取反,例如 ~1 = -2。

    00000000 00000000 00000000 00000001 // 1 的补码
~   -----------------------------------
    11111111 11111111 11111111 11111110 // -2 的补码
    10000000 00000000 00000000 00000010 // 因为是负数,反码后末位+1,得到-2的原码

按位异或^

同位只有一个为1才返回1,其余返回0。例如,1 ^ -3 = -4。

    00000000 00000000 00000000 00000001

    10000000 00000000 00000000 00000011
    11111111 11111111 11111111 11111101
^   -----------------------------------
    11111111 11111111 11111111 11111100 // -4 的补码
    10000000 00000000 00000000 00000100 // -4 的原码

有符号左移<<

符号位不动,其余补0;

8 << 2 = 32

    00000000 00000000 00000000 00001000
    -----------------------------------
    00000000 00000000 00000000 00100000

-2 << 1 = -4

    10000000 00000000 00000000 000000010 // -2 原码
    11111111 11111111 11111111 111111110 // -2 补码
    ------------------------------------
    11111111 11111111 11111111 111111100 // -4 补码
    10000000 00000000 00000000 000000100 // -4 原码

有符号右移>>

符号位不动,正数补0,负数补1;

-2 >> 1 = -1;

    10000000 00000000 00000000 000000010
    11111111 11111111 11111111 111111110
    ------------------------------------
    11111111 11111111 11111111 111111111
    10000000 00000000 00000000 000000001 // -1

无符号右移>>>

符号位也会移动,高位补0;

-2 >>> 2 =

    10000000 00000000 00000000 00000010 // -2 原码
    11111111 11111111 11111111 11111110 // -2 补码
    -----------------------------------
    00111111 11111111 11111111 11111111 // 1073741823 原码

如果你有什么位运算的妙用,可以在评论里分享一下:)