资讯专栏INFORMATION COLUMN

lodash源码收获之bitmarks

junfeng777 / 2298人阅读

摘要:文章起因近期因为对函数式编程的产生了浓厚的兴趣然后开始了的源码阅读结果开开头就看到了这样的代码当时看到这样的数列一看就知道是的次方递增跟二进制逃不了干系然后我在函数里面发现这个函数主要是由一个的函数实现然后我又进入了这个函数里面这里面有个按

文章起因

近期因为对函数式编程的curry产生了浓厚的兴趣,然后开始了lodash的源码阅读,结果开开头就看到了这样的代码

  var WRAP_BIND_FLAG = 1,
      WRAP_BIND_KEY_FLAG = 2,
      WRAP_CURRY_BOUND_FLAG = 4,
      WRAP_CURRY_FLAG = 8,
      WRAP_CURRY_RIGHT_FLAG = 16,
      WRAP_PARTIAL_FLAG = 32,
      WRAP_PARTIAL_RIGHT_FLAG = 64,
      WRAP_ARY_FLAG = 128,
      WRAP_REARG_FLAG = 256,
      WRAP_FLIP_FLAG = 512;

当时看到2,4,8,16,这样的数列一看就知道是2的次方递增,跟二进制逃不了干系.

然后我在curry函数里面发现这个函数主要是由一个 createWrap的函数 实现, 然后我又进入了这个函数里面

    var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
    
    bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);

这里面有个按位与操作,我一看这上面的操作我都懂,但是我不知道,这些操作的结果能干嘛,也不知道为什么要这么做,于是就开始了我的求知之旅.

然后看到 lodash 作者在 那一段 标记声明语句的上面 写了这么一个注释

/* Used to compose bitmasks for function metadata. /

bitmasks? 先搜一下...

bitmasks是啥

写过代码的都知道,有些操作要判断他是什么状态才执行,什么状态不执行.

那么我们就需要一些标记来帮助我们来确定,他是什么状态的.状态可不止 true false 有时候可以很多.

bitmasks 就是用来标记状态的,只不过他是用位的方式来标记.

比如: 0001,可以表示一种状态, 0011 也可以表示一种状态.

为什么要用 bitmasks

相信大家写过这样的代码,比如程序员的撸码和写文章状态.

var NOW_Status = 0;
var CODING = 1;
var WRITING = 2; 

我们可以在上面的状态中切换,我们设置状态的时候可以这样设置.

var NOW_STATUS = CODING;
if (NOW_STATUS === CODING) {
    // todo
}

如果我们的状态需要组合,比如我现在一边写文章,一边撸码,那么我们是否要定义多一个状态WRITING_CODING,来满足我们的需求呢?

学过排列与组合的就知道,当状态越多的时候,组合是成次方增长的. 所以我们得要把这个变成运算,不能手动的生成...

bitmarks 如何使用

如果使用bitmasks 状态就会变成下面这样.

var NOW_Status = 0;
var CODING = 2;
var WRITING = 4;

那么,现在我们设置状态还用 a = b 这种形式吗,既然使用了 bitmarks 那就要体现出这个 bit.

现在我们这样设置状态

    var NOW_STATUS |= CODEING

二进制就不再这里跟大家说了,程序员必备知识

这里用8位来演示,16 32 也不过是多几个0而已

NOW_STATUS: 0 => 0000 0000
CODEING: 2 => 0000 0010
按位或操作 同位两个数任意一个是1 结果就为1
得到 0000 0010 如此状态设置成功

NOW_STATES === 2

| 按位或操作是放大操作, 也就得到的数可能会比两个都大,如果前面的值是0,后面的值大于0, 那么得到的结果就是后者的本身,如此就完成了CODEING的状态设定;

若是我们要消除这个状态,普通做法是重新赋值为NO_STATUS,现在我们这样做.

    var NOW_STATUS &= ~(CODEING)

为什么要按位非,我们用按位或操作设置了值,如果我们要返回去,那么我们必须要按位与才能够返回去,因为一个为放大操作,一个为缩小操作,那么我们怎么才能返回去呢,按位与操作 相同位只要有一个0 那么结果位就是0 那么简单了 我们只要把原来放大的数的相同位的1变回0 就可以了, 在按位操作中,~ 就是这样的操作,就像这样

2 => 0000 0010
按位非后 1111 1101
在与 0000 0010 按位与
变成0000 0000 了,

看这就回去了;

我如何知道我在那个状态

如果两个大于0的相同的数 按位与,结果会返回原来的数

就像这样,

NOW_STATUS & CODEING > 0 那么就可以确定你再哪个状态了

那么如果我的状态要组合呢? 就是这两个状态随便一个都符合要求的操作, 还需要重新定义一些状态吗, 不用, 我们有或操作, 这也是符合, 一真为真,同假才假的原则.像是这样.

    var NOW_STATUS= CODEING | WRITING

nor! 状态出来了, 而且极具可读性, 一看就知道我或者在CODEING或者在WRITING.

解释:
2 | 4 对比 返回的是6 任何两个不一样的数相或 ,都不会有重复的,因此 只要你定义状态的时候 符合 1,2,4,8,16,32 这样的规律你就不会担心状态值相等;

如何确定我在这多个状态之中?

这样

NOW_STATUS & (CODEING | WRITING) != 0 

首先NOW_STATUS 是由 CODEING | WRITING 来运算出来的, 也就是说这里两个数是相等的... 两个相等的值做&操作, 返回的就是值本身, 又因为NOW_STATUS 原本就是0 所以 如果他不是0, 那么就说明这个值是由这两个状态运算得来, 也就可以确认"我"在这个状态组合里面了

bitmarks 的好处

其实在为什么要用bitmarks 的时候 出现的都是 bitmarks 的好处

但是还有一样, 就是性能, 我们知道内存中数字都是2进制存的, 那么我们操作数字的时候使用2进制的方式操作,能够节省掉那么一丝的系统资源,蚂蚁虽小也是肉!

最后

路漫漫其修远兮,吾将上下而求索.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108456.html

相关文章

  • lodash源码分析缓存使用方式的进一步封装

    摘要:但是在类中,要初始化缓存和设置缓存都需要提供和组成的二维数组,因此在类中,提供了一种更方便的缓存设置方式,只需要提供缓存的值即可。这里构造函数不需要再传入的二维数组了,只需要传入包含所有缓存值的数组即可。 在世界上所有的民族之中,支配着他们的喜怒选择的并不是天性,而是他们的观点。——卢梭《社会与契约论》 本文为读 lodash 源码的第九篇,后续文章会更新到这个仓库中,欢迎 star...

    neroneroffy 评论0 收藏0
  • lodash源码分析缓存使用方式的进一步封装

    摘要:但是在类中,要初始化缓存和设置缓存都需要提供和组成的二维数组,因此在类中,提供了一种更方便的缓存设置方式,只需要提供缓存的值即可。这里构造函数不需要再传入的二维数组了,只需要传入包含所有缓存值的数组即可。 在世界上所有的民族之中,支配着他们的喜怒选择的并不是天性,而是他们的观点。——卢梭《社会与契约论》 本文为读 lodash 源码的第九篇,后续文章会更新到这个仓库中,欢迎 star...

    wapeyang 评论0 收藏0
  • lodash源码分析数组的差集

    摘要:依赖源码分析之缓存使用方式的进一步封装源码分析之源码分析之源码分析之的实现源码分析之源码分析的调用如果有传递,则先调用,使用生成要比较数组的映射数组。循环完毕,没有在第二个数组中发现相同的项时,将该项存入数组中。 外部世界那些破旧与贫困的样子,可以使我内心世界得到平衡。——卡尔维诺《烟云》 本文为读 lodash 源码的第十七篇,后续文章会更新到这个仓库中,欢迎 star:pocke...

    Noodles 评论0 收藏0
  • lodash源码分析自减的两种形式

    摘要:作用与用法是的内部函数,之前在源码分析之缓存介绍过一种这样的数据结构这是一个二维数组,每项中的第一项作为缓存对象的,第二项为缓存的值。 这个世界需要一个特定的恶人,可以供人们指名道姓,千夫所指:全都怪你。——村上春树《当我谈跑步时我谈些什么》 本文为读 lodash 源码的第六篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash gitbook也会同步仓库的更新...

    Keven 评论0 收藏0
  • lodash源码分析isArguments

    摘要:卡尔维诺烟云本文为读源码的第二十一篇,后续文章会更新到这个仓库中,欢迎也会同步仓库的更新,地址依赖源码分析之数据类型获取的兼容性源码分析之源码分析用来判断某个值是否为类对象。如果某个值为类对象使用判断,并且调用返回的值为时,则为类对象。 有人命中注定要过平庸的生活,默默无闻,因为他们经历了痛苦或不幸;有人却故意这样做,那是因为他们得到的幸福超过了他们的承受能力。——卡尔维诺《烟云》 ...

    _Dreams 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<