使用二进制设计课堂权限
使用二进制能很方便的表达和计算(组合、切换和校验)权限,以 Linux 文件权限为例。
权限 | 字母表示 | 数字表示 | 二进制 |
---|---|---|---|
读 | r | 4 | 0b100 |
写 | w | 2 | 0b010 |
执行 | x | 1 | 0b001 |
权限之间可组合:
1 | const 读写 = 0b100 | 0b010 // 6 即 0b110 |
总的组合结果共 C(2,1) * C(2,1) * C(2,1)
,8 种,无权限 0
(---
),读权限 4
(r--
),写权限 2
(-w-
),执行权限 1
(--x
),读和写权限 6
(rw-
),读和执行权限 5
(r-x
),写和执行权限 3
(-wx
),读、写和执行权限 7
(rwx
)。
二进制运算符
二进制位运算符包括 |
(按位或 OR)、&
(按位与 AND)、^
(按位异或 XOR)、~
(按位非,取反 NOT)、<<
(左移 Left shift)、>>
(有符号右移)、>>>
(无符号右移)。
JavaScript 位运算是基于 32 位整数的,会先把 64 位浮点数转换为 32 位整数计算,计算完成后再将 32 位转为 64 位。
|
运算符
|
运算将两个操作数的每个对应位进行或运算,结果中,两个操作数对应位上至少有一个为 1
时才为 1
,否则为 0
(相当于求并),即 1 | 1 = 1
、0 | 0 = 0
、0 | 1 = 1
。
1 | 1100 |
&
运算符
&
运算将两个操作数的每个对应位进行与运算,结果中,两个操作数对应位上都为 1
时才为 1
,否则为 0
,即 1 & 1 = 1
、0 & 0 = 0
、0 & 1 = 0
。以操作数 0010
为例:
1 | xxyx |
上述例子中 x
位为任何数,&
运算的结果都是 0
,最终结果只受 y
位影响,当 y = 0
时,结果为 0000
,y = 1
时,结果为 0010
。即如果 a & b === b
为 true
,则说明 a
包含 b
。
^
运算符
^
运算将两个操作数的每个对应位进行异或运算,结果中,两个操作数对应位上不相同时才为 1
,相同时为 0
。利用这个特点,可实现 Toggle 计算。
1 | 0001 |
1 | 0011 |
~
运算符
~
将操作数的每一位取反。有点类似于反码,但不同的是,~
会将符号位也取反,而取反码,符号位不变。
1 | 1010 |
以 ~10
(~0b1010
) 为例,其 32 位二进制为 00000000000000000000000000001010
(正数的补码就是原码),~
取反得到 11111111111111111111111111110101
,由于符号位是 1
,所以这是一个负数,而计算机中存储负数是以补码的方式来存储的,所以对补码求原码再转成十进制即可,对补码求原码就是使用此补码再求一遍补码,也就是先取反码再补 1
,即 10000000000000000000000000001010
加 1
,结果为 10000000000000000000000000001011
,即 -11
。
~-2
的 32 位二进制为 11111111111111111111111111111110
(负数的补码需要反码再加 1),~
取反得到 00000000000000000000000000000001
,再将结果转为十进制,即 1
。
任何数字 x
的按位非运算结果都是 -(x + 1)
。例如,~-5
运算结果为 4
。
<<
左移运算符
将数值的二进制码向左移动一定的位(< 32),右边用 0
填充。
1 | 1010 >> 1 |
使用左移还可用来取整。位运算操作的是整数,忽略小数部分,等同于数值的整数部分,左移 0 位,结果还是整数部分。
1 | 1.111 << 0 // 1 |
>>
右移运算符
将数值的二进制码向右移动一定的位(<32),遗弃被丢出的位。
1 | 1010 >> 1 |
课堂权限设计
定义课堂黑板权限为 1
、语音权限为 2
、视频权限为 4
。权限间可组合,同时拥有黑板、语音和视频权限 Board | Audio | Video
,即 0111
。使用左移 <<
定义权限、使用按位或 |
组合权限、使用按位异或 ^
切换权限(添加或删除权限)、使用按位与 &
校验权限。
1 | // << 定义权限 |
注:如果只是单纯的添加权限,可以使用按位或 |
,单纯的删除权限,则可以先取反,再执行与操作 &(~feature)
。
1 | student.permission = student.permission &(~Permission.Audio) |