距离上一次写文章两年多的时间了,疫情这两年时间过的好快啊,快到自己像原地踏步了两年。大学的兄弟有的已经读了博士,有的工作后又考了研究生。我像是迷失在大城市的节奏里,在不知不觉中被偷走了两年。 上面说了一些废话,下面进入正题。在日常的业务需求中,我们常常需要处理一些很麻烦的业务逻辑,这里的麻烦并不是说有多复杂,而是需要增加许多
if else
,这种方式也是我处理业务逻辑的主要方法,但是写多了难免想换种方式(并没有高低之分)。前一段时间在lodash
的源码中遇到了一段懵逼的代码,google了以后了解了二进置掩码的用法。下面我介绍一下这种用法,有不妥的地方请大佬们指出。先看lodash
中的使用案例:
lodash 案例
var CLONE_DEEP_FLAG = 1,
CLONE_FLAT_FLAG = 2,
CLONE_SYMBOLS_FLAG = 4;
function baseClone(value, bitmask, customizer, key, object, stack) {
var result,
isDeep = bitmask & CLONE_DEEP_FLAG,
isFlat = bitmask & CLONE_FLAT_FLAG,
isFull = bitmask & CLONE_SYMBOLS_FLAG;
...
...
...
return result;
}
一开始看到这里的时候有点懵逼,然后上网查了一下,这里利用了二进制&
运算的特性。这样仅使用一个bitmask
变量分别对三种操作(deep、flat、symbols
)进行组合。
先看一下&
运算:
0&0=0 0&1=0 1&0=0 1&1=1
也就是同位都为1是&
才返回1,利用这个性质,上面的操作就可以被简单的表示为:
操作\ bitmask | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
deep | X | ✓ | X | ✓ | X | ✓ | X | ✓ |
flat | X | X | ✓ | ✓ | X | X | ✓ | ✓ |
symbols | X | X | X | X | ✓ | ✓ | ✓ | ✓ |
是不是很简单,bitmask
一个变量就可以表示以上所有的组合
更多用法
二进制掩码也常用于权限管理,请看下面的示例
const READ_PERMISSION_GLAF = 1;
const WRITE_PERMISSION_GLAF = 2;
const ADD_PERMISSION_GLAF = 4;
const DELETE_PERMISSION_GLAF = 8;
const test = (bitMask) => {
const canRead = bitMask & READ_PERMISSION_GLAF;
const canWrite = bitMask & WRITE_PERMISSION_GLAF;
const canAdd = bitMask & ADD_PERMISSION_GLAF;
const canDelete = bitMask & DELETE_PERMISSION_GLAF;
console.log(
`权限值:${bitMask} --- ${((bitMask).toString(2).padStart(4, '0'))}`,
'====',
`${canRead ? '读、' : ''}${canWrite ? '写、' : ''}${canAdd ? '增、' : ''}${canDelete ? '删' : ''}` || '无',
`\n`,);
}
从上图中可以看到,通过一个bitMask
我们可以判断不同的权限组合。
我们也可以对bitMask
本身做增加、删除权限的操作,还需要用到|
、~
位运算符。这里不再多说,感兴趣的小伙伴可以看一下MDN位运算符的用法。
业务中的使用
上需求:
要求是在对一条记录打上标签时,这四个分类下的标签必打(这里并没要求提示是哪一个没打哈哈)。很简单的需求,这里使用掩码实现校验的方式如下:
// Element、Language、audio、Playway 维度下标签必打
const validateTags = () => {
let index = -1;
let tagPass = 0b1111;
const { length } = store.selectedTags;
while (++index < length) {
const currentPath = store.selectedTags[index]?.path;
if (currentPath === 'Element') {
tagPass &= 0b1110;
}
if (currentPath === 'Language') {
tagPass &= 0b1101;
}
if (currentPath === 'audio') {
tagPass &= 0b1011;
}
if (currentPath === 'Playway') {
tagPass &= 0b0111;
}
if (!tagPass) break;
}
if (tagPass) {
message.error('The Playway, Element, Language, and Audio tags must be marked, please check!');
return false;
}
return true;
};
在枯燥的业务开发中,我们总要学会去更开心的写代码,希望大佬们能不吝赐教,让我学到更多愉快的代码技巧!