从Vue源码学习一些位运算小技巧

1,254 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

正文

话不多说, 直接进入正题, 在vue-next仓库中里边的package->shared->src->shapeFlags.ts里边写了这样一段枚举:

export const enum ShapeFlags {
  ELEMENT = 1,
  FUNCTIONAL_COMPONENT = 1 << 1,
  STATEFUL_COMPONENT = 1 << 2,
  TEXT_CHILDREN = 1 << 3,
  ARRAY_CHILDREN = 1 << 4,
  SLOTS_CHILDREN = 1 << 5,
  TELEPORT = 1 << 6,
  SUSPENSE = 1 << 7,
  COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
  COMPONENT_KEPT_ALIVE = 1 << 9,
  COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
}

这个枚举就是通过移位运算符去运算后获取一个值作为枚举的值. 具体运算出来的结果大概是这样的:

ShapeFlags左移运算计算结果二进制
FUNCTIONAL_COMPONENT1 << 120010
STATEFUL_COMPONENT1 << 240100
TEXT_CHILDREN1 << 381000
ARRAY_CHILDREN1 << 4160001 0000
TELEPORT1 << 5320010 0000
SUSPENSE1 << 6640100 0000
COMPONENT_SHOULD_KEEP_ALIVE1 << 71281000 0000
COMPONENT_KEPT_ALIVE1 << 82560001 0000 0000
这样看就很清楚了,左移运算每加1的话,二进制都会进1位。
COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT

然后我们接着看,在枚举以后一项,有一个按位或(|)运算描述了COMPONENT,这里就有一个位运算里边的小技巧了。 在这里COMPONENT表示的就是STATEFUL_COMPONENTFUNCTIONAL_COMPONENT都属于COMPONENT. 在后边代码里边如果要判断是否是COMPONENT的话,就这样很冗余的去判断了

if (type === ShapeFlags.STATEFUL_COMPONENT || type === ShapeFlags.FUNCTIONAL_COMPONENT) {
    // dosomething
}

我们可以去这样写:

if (type & ShapeFlags.COMPONENT) {
    // dosomething
}

如果type是STATEFUL_COMPONENT或者FUNCTIONAL_COMPONENT的话,则会得到一个非0值。 非0的话,则为ture,可以进入if判断的代码块里边去。 如果不是的话,则会返回0. 则不会进入判断里边。 这种技巧可以帮我们省下很冗余的代码。 我们在项目里边也会遇到有很多状态的情况,肯定存在需要判断状态是否是某一些状态的时候,去处理一些逻辑。 所以我们可以很好的使用这种方式去让代码更加简洁,并且可读性更高。

另外还有一个按非运算符~在项目里边也很好用。 比如我们一般写代码的话,判断数组里边是否存在某一个值,是这样判断的

let arr = [1,2,3]
if (arr.indexOf(2) > -1) {
    console.log('dosomething')
}

其实我们可以写的更简洁一点:

let arr = [1,2,3]
if (~arr.indexOf(2)) {
    console.log('dosomething')
}

原理其实就是如果不存在的话,indexOf会返回-1给我们, 那么~-1的话,算出来就是0了,0则是false,不会进入代码块里边。 如果存在的话,则是一个不为-1的其他数字, 那么~index则是一个非0的数字。 所以会进入if代码块。

结语

看别人的代码,确实还是能学到很多东西的。 尤其是像vue这种优秀的代码仓库。 很建议大家一起去多阅读这种优秀的源码。 一起加油! 那么今天就到这里了。 明天见!