前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >优雅的使用位运算,省老多事了!!!

优雅的使用位运算,省老多事了!!!

作者头像
winty
发布2024-04-15 13:31:56
860
发布2024-04-15 13:31:56
举报
文章被收录于专栏:前端Q前端Q

今天我们来一篇 JS 中的位运算科普,经常在源码中看到的位运算符,和用其定义的一系列状态到底有什么优势?

位运算符号的基本了解

首先,我们应该要简单了解位运算符,常用的位运算符大概有以下几种,我们可以在JS中使用 toString 将数字转换为二进制查看,也可以通过 0b 开头来手动创建一个二进制数字:

代码语言:javascript
复制
(3).toString(2) // 11
0b00000011 // 3 前面的几位0可以省略,可以简写为 0b11

1. 与 &

按位对比两个二进制数,如果对应的位都为 1,则结果为 1,否则为 0

代码语言:javascript
复制
console.log((1 & 3) == 1) // true

对比图例如下所示:

2. 或 |

按位对比两个二进制数,如果对应的位有一个 1,则结果为 1,否则为 0

代码语言:javascript
复制
console.log((1 | 3) == 3) // true

对比图例如下所示:

3. 异或 ^

按位对比两个二进制数,如果对应的位有且只有一个 1,则结果为 1,否则为 0

代码语言:javascript
复制
console.log((1 ^ 3) == 2) // true

对比图例如下所示:

4. 非 ~

按位对操作的二进制数取反,即 1 变 0,0 变 1,任何数的非运算符计算结果都是 -(x + 1)

代码语言:javascript
复制
const a = -1 // ~a = -(-1 + 1) = 0
console.log(~a) // 0
const b = 5 // ~b = -(5 + 1) = -6
console.log(~b) // -6

一个数和它的取反数相加的结果总为 -1

5. 左移 <<

左移会将二进制值的有效位数全部左移指定位数,被移出的高位(最左边的数字)丢弃,但符号会保留,低位(最右边的数字)会自动补0

代码语言:javascript
复制

console.log(1 << 2) // 4

图例如下所示:

6. 右移 >>

和左移相反的操作,将二进制的操作数右移指定位数,高位补0,低位丢弃!

代码语言:javascript
复制
console.log(4 >> 2) // 1

参考资料均来自 MDN,除了这些常用的符号之外,文档还标注了所有的JS操作符号,感兴趣的同学可以看一看!

有什么用?

说了这么多符号,对于操作符的影响是加深了,但是有什么用呢?二进制数字难理解,位操作符也难理解,二进制和十进制的互转不写个代码都心算不了,相信各位同学肯定有如此费解,我们先来看一段 Vue 的源代码,其中定义了很多状态类的字段!

源码位置:

https://github.com/vuejs/core/blob/main/packages/shared/src/shapeFlags.ts

以及 Vue 中对其的使用,源码位置戳这里

我们可以看到,Vue 定义了一系列状态列标识一个 Dom 是属于什么类型,并用 VNode 中的一个字段 shapeFlag 来完成存储和判断,对状态的存储只用到了一个字段一个数字,就可以进行多种状态的判断!

我们尝试着设计一种类似的判断结构出来如何?

我有N个权限

假设系统中的用户我们规定其有增删改查四个权限,我们可以设计一个枚举类来标识拥有的四个权限:

代码语言:javascript
复制
enum UserPerm {
  CREATE = 1 << 0,
  DELETE = 1 << 1,
  UPDATE = 1 << 2,
  SELECT = 1 << 3,
}

我们设计的时候,完全不必在意上述的二进制的十进制值是什么,只需要清楚的是,上述枚举的 1 在二进制位的哪个位置,如 1 的 二进制为 00000001,将其左移 1(1 << 1), 就变成了 00000010, 依次类推,我们用一个二进制串中的每一位来标识一个权限,这样一个字符串中只要出现对应位置的 1, 则该用户就拥有对应位置的权限,如图:

有什么好处呢?

我们知道二进制是可以转换为十进制的,这样子我们就可以用一个数字来表示多个权限,如一个用户完整的拥有四个权限,那他的二进制为 0b1111, 那么其状态为数字 15

如果一个用户只有 CREATESELECT 的权限,那么二进制表达为 0b1001,十进制数字为 9

后端数据库中,前端用户信息中,接口返回都只有一列一个字段就可以表示,那么用户信息应该是下面的形式:

代码语言:javascript
复制
const userInfo = {
  name: '测试1',
  phone: '15888888888',
  perm: 9, // 代表其只有 CREATE 和 SELECT 两种权限
}

权限的判断

如何判断这个用户是否具备某一个权限呢?那就需要请出我们的 与运算符(&),参考 Vue 的做法:

代码语言:javascript
复制
console.log(userInfo.perm & UserPerm.CREATE) // 9 & (1 << 0) = 1

console.log(userInfo.perm & UserPerm.UPDATE) // 返回 0, 0代表不通过

如果 userInfo.perm 中包含 CREATE,就会返回 CREATE 的值,否则返回 0,在JS中,任何非0的数字都可以通过 if 判断,所以我们只需要一个判断就足够了!

代码语言:javascript
复制
if (userInfo.perm & UserPerm.CREATE) {
  console.log('有创建权限')
} else {
  console.log('没有创建权限')
}

什么原理?我们之前给过与运算符的图例,接下来我们看一下如上两句代码的图例所示:

我们看到,上下的符号位如果对不上的话,返回的结果都是 0,这样子我们就轻松实现了权限的判断

权限的增删

那么我们如何实现对一个用户的权限更新呢,比如给上面的用户新增一个 UPDATE 权限,这个时候我们就需要 或运算符(|)

比如:

代码语言:javascript
复制
userInfo.perm | UserPerm.UPDATE // 1001 | 0100 = 1101 = 13

这样子我们就对一个用户权限进行了增加,或的规则我们上面也给过图例,这里大家可以自己尝试理解一下,无非是两个二进制数 10010100 之间的或运算,只有其中一位为 1 则为 1,这两个数字计算的结果自然是 1101

那么如何实现权限删除呢?异或运算符(^)给你答案!有且只有一个 1,返回 1,否则为 0,删除对我们刚刚添加的 UPDATE 权限的方法:

代码语言:javascript
复制
userInfo.perm ^ UserPerm.UPDATE // 1101 ^ 0100 = 1001

非常简单是吧?看到这里,相信你已经完全理解位运算符在权限系统的妙用了,如果我这个时候需要添加一个新的权限,如分享权限,那么我只有用第五位的1来表示这个权限就可以啦

代码语言:javascript
复制
enum UserPerm {
  SHARE = 1 << 5
}

// 添加分享权限
userInfo.perm | UserPerm.SHARE

以前的方案

我们以前在做用户标识的时候,通常会定义一个数组来表示,然后执行数组判断来进行权限的判断

代码语言:javascript
复制
const userPerm = ['CREATE', 'UPDATE', 'DELETE', 'SELECT']

// 判断有无权限
if (userPerm.includes('CREATE')) {
  // ...
}

// 增加权限
user.perm.push('UPDATE')

// 删除权限
user.perm.splice(user.perm.indexOf('UPDATE'), 1)

相信大家也可以看出来,无论是从内存占用,效率,便捷程度来说位运算符的形式都是完胜,这也是会被各大项目使用的原因之一!快去你的项目中实践吧,记得写好注释哦!

结语

今天带大家认识了位运算符在权限系统的妙用,小伙伴们还有什么使用位运算符的巧妙思路,可以在评论中给出来!

作者:泰罗凹凸曼 链接:https://juejin.cn/post/7244809939838844984

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-04-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端Q 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 位运算符号的基本了解
    • 1. 与 &
      • 2. 或 |
        • 3. 异或 ^
          • 4. 非 ~
            • 5. 左移 <<
              • 6. 右移 >>
              • 有什么用?
              • 我有N个权限
              • 权限的判断
              • 权限的增删
              • 以前的方案
              • 结语
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档