JS位运算

1,053 阅读7分钟

一、二进制

要了解位运算,先要知道二进制的一些知识

1. 十进制转二进制

2. 二进制转十进制

(这里是从后往前)

3. 原码、反码、补码

// 原码:一个整数,按照绝对值大小转换成的二进制数
13   ===>  0000 1101

// 反码:原码按位取反。
1111 0010

// 补码:正数的补码就是原码,负数的补码是原码的反码再加1
1111 1101

// 看一个二进制是否是正数还是负数,要先看其在计算机中是以有符号进行存储还是无符号进行存储。
// 1.如果是无符号存储,则其为一个正数。
// 2.若是有符号存储,则为补码存储。
// 3.看其最高位,最高位为0,为正数,反之,为负数。

在计算机的世界里,存储的永远是0和1,二进制的世界我们看不到,但是却一直存在。

如何把十进制转化成二进制呢?只需要把十进制一直求余2,然后整除的标0,不整除的标1,从最后一位数往前读,就是该十进制的二进制数了。

在二进制里,负数是怎么存储的呢?

其实二进制的存储分为有符号存储和无符号存储。正数的原码是它本身,反码是各位数取反,补码就是原码。负数的原码也是它本身,反码是位数取反,补码是反码+1

13
原码:0000 1101
反码:1111 0010
补码:0000 1101

-13
原码:1111 1101
反码:0000 0010
补码:0000 0011

二、位运算概览

符号 描述 运算规则
& 两个位都为1时,结果才为1
| 两个位都为0时,结果才为0
^ 异或 两个位相同为0,相异为1
~ 取反 0变1,1变0
<< 左移 各二进位全部左移若干位,高位丢弃,低位补0
>> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)
  1. &:
 /*
 	两个都为1,结果才是1(这里说的是二进制运算)
 	25 & 3 = 1
 	26 & 3 = 2
 */ 
 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
AND = 0000 0000 0000 0000 0000 0000 0000 0001

 26 = 0000 0000 0000 0000 0000 0000 0001 1010
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
AND = 0000 0000 0000 0000 0000 0000 0000 0010
  1. |:
 /*
 	两个都为0,结果才是0(这里说的是二进制运算)
 	25 | 3 = 1
 */ 
25 = 0000 0000 0000 0000 0000 0000 0001 1001 // 25 | 3 = 27
 3 = 0000 0000 0000 0000 0000 0000 0000 0011
--------------------------------------------
OR = 0000 0000 0000 0000 0000 0000 0001 1011
  1. ^:
/*
	只有一个数位存放的是 1 时,它才返回 1
	25 ^ 3 = 26
	26 ^ 3 = 25
*/
 25 = 0000 0000 0000 0000 0000 0000 0001 1001
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
XOR = 0000 0000 0000 0000 0000 0000 0001 1010

 26 = 0000 0000 0000 0000 0000 0000 0001 1010
  3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
XOR = 0000 0000 0000 0000 0000 0000 0001 1001
  1. ~
/*
	三步的处理过程:
		1. 把运算数转换成 32 位数字
		2. 把二进制数转换成它的二进制反码
		3. 把二进制数转换成浮点数
*/
var iNum1 = 25;		//25 等于 00000000000000000000000000011001
var iNum2 = ~iNum1;	//转换为 11111111111111111111111111100110
alert(iNum2);		//输出 -26
// 实质上是对数字求负,然后减 1
~undefined // 先转为数字,在求值
  1. <<: 左移
/*
	数字中的所有数位向左移动指定的数量
*/
var iOld = 2;		//等于二进制 10
var iNew = iOld << 5;	//等于二进制 1000000 十进制 64
     2 = 0000 0000 0000 0000 0000 0000 0000 0010
2 << 5 = 0000 0000 0000 0000 0000 0000 0100 0000
/* 简单来说:<< 1 ==> 移动1位 二进制10    相当于 * 2(因为二进制10等于2)
					 << 2 ==> 移动2位 二进制100   相当于 * 4(因为二进制100等于4)
					 << 3 ==> 移动3位 二进制1000  相当于 * 8(因为二进制1000等于8)
					 以此类推
	移动完了后面缺的数,用0补充
*/
  1. />>/: 右移
/*
	把 32 位数字中的所有数位整体右移,同时保留该数的符号(正号或负号)
	数字中的所有数位向右移动指定的数量
*/
// 正数
var iOld = 2;		//等于二进制 10
var iNew = iOld >> 2;	//等于二进制 10 十进制 2  2 >> 2 = 0
     2 = 0000 0000 0000 0000 0000 0000 0000 0010
2 >> 2 = 0000 0000 0000 0000 0000 0000 0100 0000 . 10(移动到这里就没了,但是不保存小数)

注意:操作数的二进制码都是其补码,正数的补码是自身,负数的补码是原码的反码+1

// 负数:左边补1    
var iOld = -2;		//等于二进制 10
var iNew = iOld >> 2;	//等于二进制 10 十进制 2  -2 >> 2 = -1
    -2 = 1111 1111 1111 1111 1111 1111 1111 1101
2 >> 2 = 1111 1111 1111 1111 1111 1111 1111 1111
// 需要保持数为负数,所以操作是对负数的二进制位左边补1

反正记住一点:右移到头了,就是-1

常用操作小技巧:

  1. 除2可以用>>1
  2. 一般^ | & 后面可以跟0、1