假如你的同事写了这样的代码:a && d || b && c && !d || (!a || !b) && c

27,115 阅读2分钟

假设看到了这样的代码:

if (a && d || b && c && !d || (!a || !b) && c) {
  console.log('pass')
} else {
  console.log('fail')
}

你是否一口老血喷在屏幕上?

当然,这段代码是我参考一个掘金沸点(@隔壁村的李二狗)伪造的,但愿你和你的同事都别这么写。

能写出这种与或非,如果不是逻辑不清,那么估计只有一种可能,需求变更很多次,多人修改后的结果。。

现在的问题是,面对如此代码,这么复杂的逻辑,能否优化?

答案是肯定的!

这种问题的探究来自于一门数学:布尔代数或逻辑代数。

说到布尔,我们开发者对此太熟悉了。不就是 true 和 false 嘛。

布尔代数这门课,大学里应该或多或少都讲些吧。因为我是数学专业毕业的,看到这种问题必须记录一下,也顺便复习一下。

为了方便表达,JS中的与或非,我用布尔代数里面的表示方法(感谢掘金支持latex公式):

a\&\&b \Rightarrow AB

a||b \Rightarrow A+B

!a \Rightarrow \overline{A}

因此 a && d || b && c && !d || (!a || !b) && c 可以表达为:

AD+BC\overline{D}+(\overline{A}+\overline{B})C

转化后优先级清晰多了。

现在的问题是,我们如何化简这个逻辑表达式。

还好有一些常用结论可供我们使用:

  1. A+A=A、A+\overline{A}=1

  2. AB+A\overline{B}=A

  3. A+AB=A

  4. \overline{A}+\overline{B}=\overline{AB}、\overline{A}\overline{B}=\overline{A+B}

  5. AB+\overline{A}C=AB+\overline{A}C+BC

前四个公式很好理解。比如A+\overline{A}=1,自己或上自己否,当然为 true。

关键在于第5个公式没那么直观,可以通过画图简单说明下(其他公式都可以类似推导)。

首先看AB部分,如图中绿色区域:

再看\overline{A}C,如图中绿色区域:

则二者之和为:

BC部分正是图中粉色区域:

因为粉色区域原本就在前二者之和里面,因此加多少BC次都是一样的。

注意最后这个公式核心特点:A\overline{A}是以和出现的。

有了这几个公式作为铺垫,我们就可以正式推导了(原沸点配图中有):

AD+BC\overline{D}+(\overline{A}+\overline{B})C

根据第4条,替换最后一项:

AD+BC\overline{D}+\overline{AB}C

注意到前两项分别有D\overline{D},符合第5条:

AD+BC\overline{D}+ABC+\overline{AB}C

此时最后两项,符合第2条:

AD+BC\overline{D}+C

最后两项,其中一项为C,另外一项也包含C,满足第3条:

AD+C

至此化简完了。真是不可以思议,B没了!

此时开篇的代码简化成了这样:

if (a && d || c) {
  console.log('pass')
} else {
  console.log('fail')
}

真清爽。

点击验证二者等价性

感谢你看到这里,希望有所帮助。

另外,在2019年末,立了个flag,数学和动画将是我今年的核心输出点。

图中二维码是我的唯一微信号,如有朋友想加的,麻烦备注下来源哈,比如“掘金”。

本文完。