JS 逻辑判断不要只知道用 if-else 和 switch条件判断(小技巧)
我们在编写JS代码时,经常会遇到逻辑判断复杂的情况。一般情况下,可以用if/else或switch来实现多个条件判断,但会出现一个问题:随着逻辑复杂度的增加,代码中的if/else和switch会越来越臃肿。本文将带你尝试写出更优雅的判断逻辑。
比如说下面这样一段代码:
constonButtonClick=(status)=>{ if(status==1){ sendLog('processing') jumpTo('IndexPage') }elseif(status==2){ sendLog('fail') jumpTo('FailPage') }elseif(status==3){ sendLog('fail') jumpTo('FailPage') }elseif(status==4){ sendLog('success') jumpTo('SuccessPage') }elseif(status==5){ sendLog('cancel') jumpTo('CancelPage') }else{ sendLog('other') jumpTo('Index') } }
你可以在代码中看到这个按钮的点击逻辑。根据活动状态的不同做两件事,发送日志埋点并跳转到相应的页面。很容易想到这段代码可以用switch重写如下:
constonButtonClick=(status)=>{ switch(status){ case1: sendLog('processing') jumpTo('IndexPage') break case2: case3: sendLog('fail') jumpTo('FailPage') break case4: sendLog('success') jumpTo('SuccessPage') break case5: sendLog('cancel') jumpTo('CancelPage') break default: sendLog('other') jumpTo('Index') break } }
好吧,看起来比if/else层次结构更清晰一些,细心的读者可能也发现了一个小窍门:case2和case3的逻辑一样时,可以把前面的逻辑处理代码省略,case2会自动执行与case3的逻辑。
不过,还有一个更简单的写法:
constactions={ '1':['processing','IndexPage'], '2':['fail','FailPage'], '3':['fail','FailPage'], '4':['success','SuccessPage'], '5':['cancel','CancelPage'], default:['other','Index'], } constonButtonClick=(status)=>{ letaction=actions[status]||actions['default'], logName=action[0], pageName=action[1] sendLog(logName) jumpTo(pageName) }
上面的代码看起来确实比较干净,这种方法的巧妙之处在于,它把判断条件作为对象的属性名,把处理逻辑作为对象的属性值。在点击按钮的时候,这种方法特别适用于单项条件判断的情况,即通过对象属性查找的方式进行逻辑判断。
这个方法很好,但是有没有其他的方法来编码呢?有的!
constactions=newMap([ [1,['processing','IndexPage']], [2,['fail','FailPage']], [3,['fail','FailPage']], [4,['success','SuccessPage']], [5,['cancel','CancelPage']], ['default',['other','Index']], ]) constonButtonClick=(status)=>{ letaction=actions.get(status)||actions.get('default') sendLog(action[0]) jumpTo(action[1]) }
使用Map代替Object有很多优点,Map对象和普通对象有的区别是:
- 一个对象通常有自己的原型,所以一个对象总是有一个“prototype”键
- 对象的键只能是一个字符串或符号,但Map的键可以是任何值
- 你可以通过使用size属性很容易得到Map中的键值对的数量,而一个对象中的键值对数量不能直接获取
现在我们来升级一下这个问题的难度。点击按钮时,不仅要判断状态,还要判断用户的身份。
constonButtonClick=(status,identity)=>{ if(identity=='guest'){ if(status==1){ //dosth }elseif(status==2){ //dosth }elseif(status==3){ //dosth }elseif(status==4){ //dosth }elseif(status==5){ //dosth }else{ //dosth } }elseif(identity=='master'){ if(status==1){ //dosth }elseif(status==2){ //dosth }elseif(status==3){ //dosth }elseif(status==4){ //dosth }elseif(status==5){ //dosth }else{ //dosth } } }
从上面的例子中可以看到,当你的逻辑升级到双重判断的时候,你的判断力就会加倍,你的代码就会加倍。
如何才能让代码更干净利落呢?
这里有一个解决方案。
constactions=newMap([ ['guest_1',()=>{}], ['guest_2',()=>{}], ['guest_3',()=>{}], ['guest_4',()=>{}], ['guest_5',()=>{}], ['master_1',()=>{}], ['master_2',()=>{}], ['master_3',()=>{}], ['master_4',()=>{}], ['master_5',()=>{}], ['default',()=>{}], ]) constonButtonClick=(identity,status)=>{ letaction=actions.get(`${identity}_${status}`)||actions.get('default') action.call(this) }
上述代码的核心逻辑是。将两个判断条件拼接成一个字符串作为Map的键,然后在查询时直接查询对应字符串的值。当然,我们也可以在这里把Map改成Object。
constactions={ guest_1:()=>{}, guest_2:()=>{}, //.... } constonButtonClick=(identity,status)=>{ letaction=actions[`${identity}_${status}`]||actions['default'] action.call(this) }
如果读者觉得把查询拼成一个字符串有点尴尬,还有另一个解决办法,那就是用一个Map对象作为key。
constactions=newMap([ [{identity:'guest',status:1},()=>{}], [{identity:'guest',status:2},()=>{}], //... ]) constonButtonClick=(identity,status)=>{ letaction=[...actions].filter(([key,value])=>key.identity==identity&&key.status==status) action.forEach(([key,value])=>value.call(this)) }
这里你也可以看到Map和普通对象的区别,其中Map可以用任何类型的数据作为键。现在让我们把它的难度再提高一点。如果对于guest身份来说,状态1-4的处理逻辑是一样的呢?
最坏的情况是这样的(代码大量重复):
constactions=newMap([ [{identity:'guest',status:1},()=>{}], [{identity:'guest',status:2},()=>{}], [{identity:'guest',status:3},()=>{}], [{identity:'guest',status:4},()=>{}], [{identity:'guest',status:5},()=>{}], //... ])
更好的方法是把处理逻辑函数分离出来:
constactions=()=>{ constfunctionA=()=>{} constfunctionB=()=>{} returnnewMap([ [{identity:'guest',status:1},functionA], [{identity:'guest',status:2},functionA], [{identity:'guest',status:3},functionA], [{identity:'guest',status:4},functionA], [{identity:'guest',status:5},functionB], //... ]) } constonButtonClick=(identity,status)=>{ letaction=[...actions()].filter(([key,value])=>key.identity==identity&&key.status==status) action.forEach(([key,value])=>value.call(this)) }
这对于日常需求来说已经足够了,但是说真的,函数A被引用了4次,还是有点烦人。
如果事情真的变得很复杂,比如身份有3种,状态有10种,你需要定义30个处理逻辑,其中很多处理逻辑都是一样的,这似乎让人无法接受。
而你可以这样做:
constactions=()=>{ constfunctionA=()=>{}//逻辑处理A constfunctionB=()=>{}//逻辑处理B returnnewMap([ [/^guest_[1-4]$/,functionA], [/^guest_5$/,functionB], //... ]) } constonButtonClick=(identity,status)=>{ letaction=[...actions()].filter(([key,value])=>key.test(`${identity}_${status}`)) action.forEach(([key,value])=>value.call(this)) }
这时使用Map而不是Object的优势比较明显,因为可以用正则式作为键。
如果需求变成:所有的对guest操作都需要发送一个日志埋点,不同状态的guest可能有不同的逻辑处理,那么我们可以写成如下:
constactions=()=>{ constfunctionA=()=>{}//逻辑处理A constfunctionB=()=>{}//逻辑处理B constfunctionC=()=>{}//发送日志C returnnewMap([ [/^guest_[1-4]$/,functionA], [/^guest_5$/,functionB], [/^guest_.*$/,functionC], //... ]) } constonButtonClick=(identity,status)=>{ letaction=[...actions()].filter(([key,value])=>key.test(`${identity}_${status}`)) action.forEach(([key,value])=>value.call(this)) }
这样一来,公共逻辑和单个逻辑可以同时执行。
总结
本文讲到了八种JS逻辑判断的写法,包括:
- if/else
- switch
- 单一判断:存储在Object中
- 单一判断:存储在Map对象中
- 多重判断:将条件串联成一个字符串,存储在Object中
- 多重判断:将条件连成一个字符串,存储在Map对象中
- 多重判断:把条件作为对象存储在Map中
- 多重判断:把条件写成正则式存储在Map中
到此这篇关于JS逻辑判断不要只知道用if-else和switch条件判断的文章就介绍到这了,更多相关js逻辑判断ifelseswitch内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。