Js位运算符

801 阅读5分钟

相关概念

概念:位运算在数字底层(表示数字的32个数位)进行运算的。因为是运算的低级运算操作,所以运算速度往往也是最快的,但是他很不直观。

位运算只对整数起作用,如果一个运算不是整数,会自动转为整数后再运行。

虽然在JavaScript内部,数值都是以64位浮点数的形式存储,但是做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是32位带符号的整数

这种转换使得在对特殊的NaN和infinity值应用位操作时,这两个值会被当成0来处理。如果是对非数值用位操作时,会先使用**Number()**方法将值转换成数值再应用位操作。

二进制:ECMAScript整数有两种类型,即有符号整数(允许用正数和负数)和无符号整数(只允许用正数)。在ECMAScript中,所有整数字面量默认都是有符号整数。

有符号整数使用31位表示整数的数值,用第32位表示整数的符号,0表示正数,1表示负数。数值从-2147483648 到 2147483647。表示符号的位叫做符号位,符号位的值决定了其他位数值的格式。其中,正数以纯二进制格式存储,31位中的每一位都表示2的幂,第一位(叫做位0)表示2的1次以此类推,没有用到的位以0填充,可以忽略不计。

举例分析

如:数字10的表示法

10的二进制是‘1010’,它只用了前4位,这4位是有效位。其他的数位可以忽略不计。

console.log((10).toString(2)); //1010

反推的话

负数可以存储位二进制代码,不过采用的形式是二进制补码,计算数字二进制补码的步骤如下:

1、确定数字的非负版本的二进制表示

2、求得二进制反码要把0替换为1,1替换为0

3、在二进制反码后加1

如:确定-10的二进制补码为

第一步:10的二进制表示为 0000 0000 0000 0000 0000 0000 0000 1010

第二步:1和0互换 1111 1111 1111 1111 1111 1111 1111 0101

第三步:二进制反码+1

所以-10的二进制表示是1111 1111 1111 1111 1111 1111 0110。需要注意的一点是在处理有符号的整数是不能访问31位。但是,把负整数转换成二进制字符串后,ECMAScript并不是以二进制补码形式显示,而是用数字绝对值的标准二进制代码前加负号的形式输出,这是为了避免访问位31位,为了方便。

例如:console.log((-10).toString(2)) // -1010

位运算可以进行7种运算,包括按位非(NOT),按位与(AND),按位或(OR),按位异或(XOR),左移,有符号右移,无符号右移

具体分析

1、按位非(NOT)

按位非操作符有一个波浪线(~)表示,操作他可以返回数值的反码,其本质是操作数的负值减1,对一个整数两次按位非得到它的自身,对于小数两次按位非可以得到取整的效果

<script>        
    let n = 9;        
    let i = 9.9;        
    let m = ~n;        
    console.log(m); //-10  (9负值后再减1得到-10)        
    console.log(~~n);//9  (9负值后再减1得到-10,-10负值后再减1的到9)
    console.log(~~i);//9 (位运算前会将小数转为整数)
</script>

2、按位与(AND)

按位与操作符由一个和符号(&)表示,它由两个操作数。直接对数字的二进制形式进行运算。它把每个数字中的数位对齐,然后用下面 的规则对同一位置上的两个数位进行AND运算。按位与操作只有在两个数值的对应位都是1时才返回1,任何一位时0结果都位0

<script>        
    let n = 10;        
    let m = 15;        
    console.log(n & m);  //10        
    console.log(n.toString(2), m.toString(2)); //1010 1111  
</script>

分析如下:

3、按位或(OR)

按位或操作符由一个竖线(|)符号表示,也是有两个操作符,按位或操作按照下表来进行。有一个位置是1的情况下就返回1,而只有在两个位数都是0的情况下才是0。一个整数与0按位或可以得到它本身,一个小数与0按位或可以得到取整的效果。

<script>        
    let n = 10;        
    let m = 15;        
    console.log(n | m);    //15 	
    console.log(n.toString(2), m.toString(2)); //1010 1111        
    console.log(3.9 | 0);  //3        
    console.log(4.1 | 0);   //4  
</script>

4、按位异或(XOR)

它由一个插入符号(^)表示,也需要两个操作数,以下是真值表。按位异或的两个数值相同时返回0,不同时返回1。一个整数与0按位异或可以保持自身,一个小数与0异或可以取整

<script>
        let n = 10;
        let m = 15;
        console.log(n ^ m);  //5
        console.log(n.toString(2), m.toString(2)); //1010 1111 
</script>

^ 有一个特殊的运用,连续对两个数a和b进行三次异或运算,a^=b,b^=a,a^=b可以互换它们的值。这意味着,使用^可以在不引入临时变量的前提下,互换两个变量的值

<script>
        let a = 10, b = 11; // 1010   |   1100
        a ^= b;  // 1010  ^  1100  = 0110
	b ^= a; //  1100 ^ 0110 = 1010
	a ^= b; //  0110 ^  1010 = 1100
        console.log(a, b); //11 10
</script>

5、左移

左移操作符由两个小于号(<<)表示,这个操作符会吧数值的所有位向左移动指定的位数。

如:将数值3(二进制位11)向左移动5位,结果就是96

<script>
       let n=3;
       let m=n<<5;
       console.log(n.toString(2)); //11
       console.log(m); //96 
</script>

6、有符号右移

由两个大于号(>>)表示,将数值向右移动,保留符号位。有符号右移操作与左移操作正好相反,如96向右移动5位变成3.

7、无符号右移

它是由三个大于号表示(>>>),这个操作符会将数值的所有32位都向右移动,对于正数来说,无符号右移和有符号右移结果相同。但是对于负数来说,无符号右移是以0来填充空位。还有一点是,无符号右移操作符会把负数的二进制码当成正数的二进制码且由于负数以其绝对值的二进制补码形式表示,所以会导致无符号右移后的结果非常大。

如:-95无符号右移5

<script>
        let n = -96;
        console.log(n >>> 5);//134217725
</script>

分析:

三、常用的运算

利用 << 来实现乘法运算;利用 >> 实现除法运算;利用 ^ 来实现值的互换;小树取整;

<script>
        console.log(4 << 1);//8        4*Math.pow(2,1)
        console.log(4 << 2);//16         4*Math.pow(2,2)
        console.log(4 << 3);//32         4*Math.pow(2,3)
        console.log(4 << 4);//64         4*Math.pow(2,4)
        console.log(4 << 5);//128         4*Math.pow(2,5)
        console.log(4 << 6);//256          4*Math.pow(2,6)

        console.log(5 >> 3);//0        parseInt(5/Math.pow(2,3))
        console.log(14 >> 2);//3        parseInt(5/Math.pow(2,2))
        console.log(225 >> 5);//7        parseInt(5/Math.pow(2,5))

        let a = 20, b = 4;
        a ^= b, b ^= a, a ^= b;
        console.log(a, b);//4 20


        console.log(~~9.9);//9
        console.log(9.8 | 0);//9
        console.log(9.7 ^ 0);//9
        console.log(9.6 << 0);//9
        console.log(9.3 >> 0);//9

    </script>