在某个业务场景中,需要判断某应用需要的权限,在之前,我很可能会使用if,else,或者switch语句来获取或者改变其某个权限的状态,今天了解到了还有通过巧用位运算中的按位异或和按位与来操作,真的是涨姿势了,话不多说先看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//以下声明了该应用需求的4个权限获取的状态,数值为2的整数幂的值,以便转换二进制来判断权限
const READ_MSG = 1
const DEL_MSG = 2
const READ_TEL = 4
const DEL_TEL = 8
let result

//传入某权限的状态码总和以及需要查询的权限,使用按位与来获取某权限的状态
function getPermissionStatus(permission, code) {
result = permission & code //①
if(result === 0) {
return "权限关闭"
}
return "权限开启"
}
//传入某权限的状态码总和以及需要改变的权限,使用按位异或改变该权限的状态
function changePermissionStatus(permission, code) {
result = permission ^ code //②
return result
}

let permission = 11 //这里是获取的权限的权限码总和
let DelTelStatus = getPermissionStatus(permission, DEL_TEL)
console.log(DelTelStatus) //权限开启

let newPermission = changePermissionStatus(permission, DEL_TEL)
let ChangedDelTelStatus = getPermissionStatus(newPermission, DEL_TEL)
console.log(ChangedDelTelStatus) //权限关闭 改变成功

该应用需要的权限

权限名权限值权限值(二进制)
READ_MSG10000 0001
DEL_MSG20000 0010
READ_TEL40000 0100
DEL_TEL80000 1000

①将权限码总和与需要查询的某权限的权限码做按位与运算

这里我选择了DEL_TEL这个权限,其权限码二进制为0000 1000,权限码总和为0000 1011

1
2
3
4
5
0000 1000
&
0000 1011
=
0000 1000

我们会发现按位与运算后的结果不等于0,表示其拥有DEL_TEL这个权限,再尝试换READ_TEL这个权限试验:

1
2
3
4
5
0000 0100
&
0000 1011
=
0000 0000

这时结果为0了,表示其没有READ_TEL的权限,确认无误。

②将权限码总和与需要改变的某权限的权限码做按位异或运算

1
2
3
4
5
0000 1000
^
0000 1011
=
0000 0011

这时候我们再用结果的0000 0011和其DEL_TEL权限码做按位与运算发现其DEL_TEL的权限没有了:

1
2
3
4
5
0000 0011
&
0000 1000
=
0000 0000

按位运算带来的影响

基于位运算实现权限管理系统时,其运算运算对象是二进制数,优点是:运算速度快、效率高、节省存储空间、对权限控制非常灵活。所有语言都提供了位运算符,我们可以在不同语言实现的系统、甚至数据库中使用位运算实现对用户权限的管理。
位运算也有一些局限性,随着权限码增加,数据长度也相应的增长。这就要求权限码不能超过计算本身运算长度,在数据库中存储权限码时,权限码长度也不能的超过所使用数据类型。如:在32位系统中不能超过232,也就是权限数量不能多于32个。而mySQL数据库的BIGINT,其存储空间为8Byte,使用BIGINT存储存储码时,权限数不能多于64个(8*8-1)。