这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
什么是位运算?
位运算是在数字底层(即表示数字的 32 个数位)进行运算的。由于位运算是低级的运算操作,所以速度往往也是最快的(相对其它运算如加减乘除来说),并且借助位运算有时我们还能实现更简单的程序逻辑,缺点是很不直观,许多场合不能够使用。
js位运算符总共分为两类:
逻辑位运算符:位与(&)、位或(|)、位异或(^)、非位(~)
移位运算符:左移(<<)、右移(>>)、全右移(>>>)
- 逻辑运算符
- 位与(
&): 真真为真(1),其余为假(0)
var a = 1;
var b = 2;
console.log(a & b)
计算的过程如下:首先会把a 和 b 的值都转成二进制的数据(这里转换的数据是32的二进制哦),然后进行运算
注意: 位运算
与可以用于 b 中是否包含 a ,这个包含是指的是二进制的数据是否包含交集,具体的表达式如下:(a & b) === a
- 位或(
|): 假假为假(0),其余为真(1)
var a = 1, b = 2;
console.log(a | b)
计算过程如下:
注意: 这个功能一般常用来取两个二进制数据的
并集
- 位异或(
^):相同为假(0),不同为真(1)
var a = 1, b = 3;
console.log(a ^ b)
运算过程如下:
注意: 异或运算一般可以用于做
减法,通过更大的那个值来除去那个小的值,还剩多少
- 非位(
~):真为假,假为真
var num = 1;
var num1 = ~num;
console.log(~num1 )
js存储的的负数一般要经过以下步骤,才可以进行存储。
- 将
真码变成反码, 就是说把所有的 0 都变成1- 把
反码变成补码, 就是说在反码的基础上加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
- 移位运算符
- 左移(
<<):首位符号为不动,把32位二进制数字整体往左边移动指定位数,左边超出部分被舍去,右边补0
9二进制有符号左移5位
9<<5
0000000000000000 0000000000001001
------
0000000000000000 0000000100100000
公式:
计算机内是这样位移计算的,实际应用计算我们可以通过公式:
num * (2^n),即:9*Math.pow(2,5)
- 右移(
>>):首位符号为不动,把32位二进制数字整体往右边移动指定位数,右边超出部分被舍去,左边补0,这可能会丢失数据。
3二进制有符号右移5位
3>>1
0000000000000000 0000000000000011
------
0000000000000000 0000000000000001
公式:
- 无符号右移(
>>>):符号为也跟着一起移动,这样,无符号右移会把负数的二进制当成整数的二进制码
案列
// 运用场景,想要实现一个权限控制
enum Permission {
Read = 1,
Write = 2,
Create = 4,
Delete = 8
}
let p: Permission = Permission.Read | Permission.Write;
function hasPermission(target: Permission, per: Permission) {
return (target & per) === per;
}
p = p ^ Permission.Write;
console.log(hasPermission(p, Permission.Write));
本文使用 文章同步助手 同步