引言
在实际开发当中,我们经常会需要处理组件的封装以及相应的参数传递,如何能用更少更简单的入参调用实现所需的场景,这对于组件封装者来说的确是需要考虑的一件事。
举这样一个例子,笔者封装了一个资讯列表的Tab
页,提供各个板块的资讯信息,现在需要把这样一个组件对外暴露,要求能够通过更少的参数配置帮助调用方实现所需板块的资讯列表展示。
一些尝试
如果封装组件的 Tab
比较少的情况下,我们可以通过布尔值的配置来实现相应内容的展示,例如:
jsx
return <Information
isShowIntroduction={true} // 配置推荐
isShowFollow={true} // 配置关注
isShowHot={true} // 配置热榜
></Infomation>
但如果 Tab
有 10 个甚至更多,一个个传布尔值参数就不是一个好的做法了。
当然我们也可以传入一个 tabCode
的数组,例如:
jsx
return <Information
tabs={[0, 2, 3, 5, 8]}
></Infomation>
这样也不是不行,只不过传入引用类型的参数背后可能还是会需要一系列的逻辑来将其处理成简单的基础类型来进行比对,那我们就想,能否通过传入一个有特点的参数来区分不同的板块组合?当然是可以的,不卖关子,直接来说一说我们的主角------位运算
。
JavaScript 位运算
运算符 | 名称 | 描述 |
---|---|---|
& | AND | 如果两位都是 1 则设置每位为 1 |
| | OR | 如果两位之一为 1 则设置每位为 1 |
^ |
XOR | 如果两位只有一位为 1 则设置每位为 1 |
~ | NOT | 反转所有位 |
<< | 零填充左位移 | 通过从右推入零向左位移,并使最左边的位脱落。 |
>> | 有符号右位移 | 通过从左推入最左位的拷贝来向右位移,并使最右边的位脱落。 |
>>> | 零填充右位移 | 通过从左推入零来向右位移,并使最右边的位脱落。 |
我们这里只会用到 &
和 <<
操作 | 结果 | 等同于 | 结果 |
---|---|---|---|
5 & 1 | 1 | 0101 & 0001 | 0001 |
5 << 1 | 10 | 0101 << 1 | 1010 |
ini
0 1 0 1 = 5
& 0 0 0 1 = 1
------------
0 0 0 1 = 1
可以看到 & 运算
,两个二进制数只有末位数都全是 1 ,其它位都有 0 存在,所以他的结果是 1,而 << 运算
,0101 左移之后末尾补 0 变成了 1010,也就是 10。
位运算处理法
利用这个特性,我们可以做如下操作:
js
// 假设我们封装的组件提供以下 tab 名称的板块内容,并按顺序排列
const tabArr = ["推荐", "关注", "热榜", "亚运会", "发现", "当地", "听书", "小视频", "小说"];
- 获取需要展示的板块的下标,并左移下标数,将所有结果做累加
- 左移的目的是保证从右数 n + 1 项为 1, 后续利用二进制 & 运算每一位只有都是 1 才真正是 1 的特性做比对,即找到 n + 1 项为 1 的那个下标对应的板块
js
// 假设我们需要展示:["推荐", "关注", "热榜", "当地", "小说"],对应的下标分别是:[0, 1, 2, 5, 8]
const tabsTotalIndex = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 5) + (1 << 8); // 295
也就是说,调用方只需要根据封装组件提供的 tabArr
说明,传入 tabs = 295
即可,也就是:
jsx
// ["√推荐", "√关注", "√热榜", "亚运会", "发现", "√当地", "听书", "小视频", "√小说"]
const tabsTotalIndex = (1 << 0) + (1 << 1) + (1 << 2) + (1 << 5) + (1 << 8);
return <Information tabs={tabsTotalIndex} />
此时封装的组件需要根据传入的 tabs
做如下处理:
js
// tabs = 295;
const tabArr = ["推荐", "关注", "热榜", "亚运会", "发现", "当地", "听书", "小视频", "小说"];
const newTabArr = tabArr.filter((_, key) => {
const num = 1 << key;
return (tabs & num) === num;
}); // ["推荐", "关注", "热榜", "当地", "小说"]
最终,我们得到调用方实际需要的板块 newTabArr
进行展示。
当然,这个例子中的 tabArr
只是为了便于说明,实际项目中肯定不会是这么简单的字符串数组,不过相信从这个例子中能够体会到位运算带来的便利,其实它还有很多的妙用,以及一系列的骚操作,这里就不做延展了,有兴趣的自己去发现喽!