位运算
按位与&
对每对比特位执行与(AND)操作。只有 a 和 b 都为1时,a & b 就是 1。如下表9 & 3 = 1
9 | = | 1 | 0 | 0 | 1 |
---|---|---|---|---|---|
3 | = | 0 | 0 | 1 | 1 |
1 | = | 0 | 0 | 0 | 1 |
由上表我们可以清晰的看出按位与的计算规则,由此可以引出一系列应用场景
判断奇偶
我们知道奇数的二进制最后一位必然为1,所以任意一个奇数 & 1 一定等于1。
// 判断奇偶
return number & 1 === 1
按位或 |
对每对比特位执行与(AND)操作。只有 a 和 b 任意一位为1时,a | b 就是 1。如下表9 | 3 = 11
9 | = | 1 | 0 | 0 | 1 |
---|---|---|---|---|---|
3 | = | 0 | 0 | 1 | 1 |
11 | = | 1 | 0 | 1 | 1 |
取整
对于一般的整数,返回值不会有任何变化。对于大于2的32次方的整数,大于32位的数位都会被舍去。
function toInt(num) {
return num | 0
}
console.log(toInt(1.8)) // 1
console.log(toInt(1.23232)) // 1
按位非 ~
对每一个比特位执行非(NOT)操作。NOT a 结果为 a 的反转(即反码)。
ps: 对任一数值 x 进行按位非操作的结果为 -(x + 1)。例如,~5 结果为 -6:
负数存储采用的形式是二进制补码。计算数字二进制补码的步骤有三步:
1.确定该数字的非负版本的二进制表示(例如,要计算 -18的二进制补码,首先要确定 18 的二进制表示)
2.求得二进制反码,即要把 0 替换为 1,把 1 替换为 0(相当于~操作)
3.在二进制反码上加 1
我们可以看到一个数a取负相当于 ~a + 1, 即 -a = ~a + 1, 因此~a = -(a + 1)
应用场景:
取整 (位运算花样取整)
~~(-5.88) // -5
判断数组中某项是否存在
// 常用判断
if (arr.indexOf(item) > -1) {
// code
}
// 按位非 ~-1 = - (-1 + 1)
if (~arr.indexOf(item)) {
// code
}
按位异或 ^
对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
其运算法则相当于不带进位的二进制加法
9 | = | 1 | 0 | 0 | 1 |
---|---|---|---|---|---|
3 | = | 0 | 0 | 1 | 1 |
10 | = | 1 | 0 | 1 | 0 |
应用场景:
切换变量0和1
假如我们通过某个条件来切换一个值为0或者1
function update(toggle) {
num = toggle ? 1 : 0;
}
update(true);
// 通过异或我们可以这么写
num = num ^ 1;
交换两个变量的值(不用第三个变量)
let a = 5,
b = 6;
a = a ^ b;
b = a ^ b;
a = a ^ b;
// 还可以通过运算
a = a + b;
b = a - b;
a = a - b;
// es 6
[a, b] = [b, a]
原理剖析:a = a ^ b; b = a ^ b 相当与 b = a ^ b ^ b = a ^ (b ^ b) = a ^ 0 = a;
按位移动操作符
按位移动操作符有两个操作数:第一个是要被移动的数字,而第二个是要移动的长度。移动的方向根据操作符的不同而不同。
按位移动会先将操作数转换为大端字节序顺序(big-endian order)的32位整数,并返回与左操作数相同类型的结果。右操作数应小于 32位,否则只有最低 5 个字节会被使用。
左移 <<
该操作符会将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充。
例如 3 << 2 的运算图示如下:
3 = 0000 0000 0000 0000 0000 0000 0000 0011
12 = 0000 0000 0000 0000 0000 0000 0000 1100
ps: 对任一数值 x 进行左移n, 相当于十进制里的乘以10的倍数,在这儿是指
x * 2^n
右移 >>
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用 0 补充。
例如 8 >> 1 的运算图示如下:
3 = 0000 0000 0000 0000 0000 0000 0000 1000
12 = 0000 0000 0000 0000 0000 0000 0000 0100
ps: 对任一数值 x 进行右移n, 相当于十进制里的除以10的倍数,在这儿是指
x / (2^n)
状态控制
现在有权限1,权限2,权限3; 3种权限;
// 定义三种权限状态分别为1、2、4;
let 权限1 = 1 << 0; // 1 -> 001
let 权限2 = 1 << 1; // 2 -> 010
let 权限3 = 1 << 2; // 4 -> 100
每中角色拥有不同的权限组合;admin拥有所有权限,guest拥有权限2和权限3;
let admin = 权限1 | 权限2 | 权限3; // 7 -> 111
let guest = 权限2 | 权限3; // 3 -> 011
1. 如何判断角色拥有对应的权限?
// 判断admin是否拥有权限1
if(admin & 权限1 === 权限1){
console.log("admin拥有权限1")
}
// 判断guest是否没有权限1
if(guest & 权限1 !== 权限1){
console.log("guest没有权限1")
}
// 判断guest是否拥有权限2、3
if(guest & (权限2 | 权限3) === (权限2 | 权限3)){
console.log("guest拥有权限2、3")
}
2. 如何为guest赋予权限?
if(guest & 权限1 !== 权限1){
// 赋予单个权限
guest |= 权限1;
// 赋予多个权限
guest |= (权限1 | 权限n);
}
console.log("guest是否拥有权限1:", guest & 权限1 === 权限1);
3. 如何取消guest的权限?
3.1:
if(guest & 权限2 === 权限2){
// 取消单个权限;
guest &= ~权限2;
// 取消多个权限;
guest &= ~(权限2 | 权限n);
}
3.2:
if(guest & 权限2 === 权限2){
// 取消单个权限;
guest ^= 权限2;
// 取消多个权限;
guest ^= 权限2 | 权限n;
}
& 判断是否拥有某个状态
|= 添加某个状态
^= 反转(取消)某个状态
整理
奇偶数判断:n & 1 === 1;
取整:(~~1.58) == (1.58 | 0) == 1;
0、1切换:x ^ 1;注:x = 0 | 1;
https://www.kancloud.cn/surahe/front-end-notebook/1616873
https://blog.csdn.net/linxijun120903/article/details/78592313