js 位运算符
什么是位运算?
位运算是在数字底层(即表示数字的 32 个数位)进行运算的。由于位运算是低级的运算操作,所以速度往往也是最快的(相对其它运算如加减乘除来说),并且借助位运算有时我们还能实现更简单的程序逻辑,缺点是很不直观,许多场合不能够使用。
js位运算符总共分为两类:
逻辑位运算符:位与(&)、位或(|)、位异或(^)、非位(~)
移位运算符:左移(<<)、右移(>>)、全右移(>>>)
- 逻辑运算符
1.位与(&): 真真为真(1),其余为假(0)
var a = 1; var b = 2; console.log(a & b) // 结果是:1
计算的过程如下:首先会把a 和 b 的值都转成二进制的数据(这里转换的数据是32的二进制哦),然后进行运算
注意: 位运算 与 可以用于 b 中是否包含 a ,这个包含是指的是二进制的数据是否包含交集,具体的表达式如下: (a & b) === a
2.位或(|): 假假为假(0),其余为真(1)
var a = 1, b = 2; console.log(a | b) // 结果是 3
计算过程如下:
注意: 这个功能一般常用来取两个二进制数据的并集
3.位异或(^):相同为假(0),不同为真(1)
var a = 1, b = 3; console.log(a ^ b) // 输出结果是 2
运算过程如下:
注意: 异或运算一般可以用于做减法,通过更大的那个值来除去那个小的值,还剩多少
4.非位(~):真为假,假为真
var num = 1; // 二进制 00000000000000000000000000000001 var num1 = ~num; // 二进制 11111111111111111111111111111110 console.log(~num1 ) // 结果是-2
js存储的的负数一般要经过以下步骤,才可以进行存储。
1.将真码变成反码, 就是说把所有的 0 都变成1
2.把反码变成补码, 就是说在反码的基础上加1,然后这个表示的才是一个存储的数据,当拿来运算的时候,需要逆向转换, 先减1,返回在取反
我们知道,js中的数字默认是有符号的。有符号的32位二进制的最高位也就是第一位数字代表着正负,1代表负数,0代表整数。那到底11111111111111111111111111111110等于多少呢?最高位为1代表负数,负数的二进制转化为十进制:符号位不变,其他位取反加1。取反之后为10000000000000000000000000000001,加1之后为10000000000000000000000000000010,十进制为-2。
注意:这个运算符的妙用可以使用在 判断值是否为-1上,例如:const filters = ['aa', 'bb', 'c']; if (~filters.indexOf(a)) {} 而不是 if( filters.indexOf(a) != -1 ) or if( filters.indexOf(a) >= 0), 如果取一个数字的整数,可以直接使用~~数字
这里还有一个计算非运算的技巧:
取非运算的时候,先把数据前面加一个负号, 然后在减1
- 移位运算符
5.左移(<<):首位符号为不动,把32位二进制数字整体往左边移动指定位数,左边超出部分被舍去,右边补0
9二进制有符号左移5位 9<<5 0000000000000000 0000000000001001 ------ 0000000000000000 0000000100100000
公式:数字1×2数字2
计算机内是这样位移计算的,实际应用计算我们可以通过公式:num * (2^n) ,即:9*Math.pow(2,5)
6.右移(>>):首位符号为不动,把32位二进制数字整体往右边移动指定位数,右边超出部分被舍去,左边补0,这可能会丢失数据。
3二进制有符号右移5位 3>>1 0000000000000000 0000000000000011 ------ 0000000000000000 0000000000000001
公式:
7.无符号右移(>>>):符号为也跟着一起移动,这样,无符号右移会把负数的二进制当成整数的二进制码
案列
// 运用场景,想要实现一个权限控制
// 我们使用一个枚举,或者一个对象都行 enum Permission { Read = 1, // 0001 Write = 2, // 0010 Create = 4, // 0100 Delete = 8 // 1000 } // 使用一个权限组, 需要哪个权限就使用 位或 运算符进行 //使用或运算 //0001 //或 //0010 //0011 let p: Permission = Permission.Read | Permission.Write; //2. 如何判断是否拥有某个权限 //0011 //且 //0010 //0010 function hasPermission(target: Permission, per: Permission) { return (target & per) === per; } //判断变量p是否拥有可读权限 //3. 如何删除某个权限 //0011 //异或 //0010 //0001 p = p ^ Permission.Write; console.log(hasPermission(p, Permission.Write));