记一次前端业务中二进制掩码的使用

486 阅读3分钟

距离上一次写文章两年多的时间了,疫情这两年时间过的好快啊,快到自己像原地踏步了两年。大学的兄弟有的已经读了博士,有的工作后又考了研究生。我像是迷失在大城市的节奏里,在不知不觉中被偷走了两年。 上面说了一些废话,下面进入正题。在日常的业务需求中,我们常常需要处理一些很麻烦的业务逻辑,这里的麻烦并不是说有多复杂,而是需要增加许多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,利用这个性质,上面的操作就可以被简单的表示为:

操作\ bitmask01234567
deepXXXX
flatXXXX
symbolsXXXX

是不是很简单,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`,);
}

image.png

从上图中可以看到,通过一个bitMask我们可以判断不同的权限组合。 我们也可以对bitMask本身做增加、删除权限的操作,还需要用到|~位运算符。这里不再多说,感兴趣的小伙伴可以看一下MDN位运算符的用法。

业务中的使用

上需求:

image.png 要求是在对一条记录打上标签时,这四个分类下的标签必打(这里并没要求提示是哪一个没打哈哈)。很简单的需求,这里使用掩码实现校验的方式如下:

// 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;
  };

在枯燥的业务开发中,我们总要学会去更开心的写代码,希望大佬们能不吝赐教,让我学到更多愉快的代码技巧!

安利时间!在找工作的朋友看过来(是否前端方向都行),公司名小影科技,在杭州西湖区,基本待遇:六险一金、弹性时间、双休。

详细待遇和要求boss上找到职位直接聊,或者问我也行(仅限前端,知道的越多越危险哈哈)。下面是内推码,感兴趣的朋友看看,让我们异世相遇,尽享美味!

image.png