当前位置: 首页 > Web前端 > HTML

JavaScript复杂判断的一种更优雅的写法

时间:2023-04-02 23:05:41 HTML

前提条件我们在写js代码的时候,经常会遇到复杂的逻辑判断。通常可以使用if/else或者switch来实现多个条件判断,但是这样会有问题。随着逻辑复杂度的增加,代码中的if/else/switch会越来越臃肿难懂,那么如何写出更优雅的判断逻辑,本文就带你去尝试一下。比如我们看一段代码/***按钮点击事件*@param{number}status活动状态:1团开始进行中2团开始失败3商品售罄4团开始成功5系统取消*/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')}}通过代码可以看到这个按钮的点击逻辑:根据代码做两件事针对不同的活动状态,发送日志埋点并跳转到相应的页面。您可以轻松地为这段代码提出重写计划。开关出现:/***按钮点击事件*@param{number}status活动状态:1团进行中2开团失败3商品售罄4成功开团5系统取消*/constonButtonClick=(status)=>{switch(status){case1:sendLog('processing')jumpTo('IndexPage')breakcase2:case3:sendLog('fail')jumpTo('FailPage')breakcase4:sendLog('success')jumpTo('SuccessPage')中断案例e5:sendLog('cancel')jumpTo('CancelPage')breakdefault:sendLog('other')jumpTo('Index')break}}嗯,这个看起来比if/else清楚多了,细心的同学也发现了一个小把戏。当case2和case3的逻辑相同时,可以省略执行语句和break,在case2的情况下会自动执行case3的逻辑。这时候有同学会说有更简单的写法:constactions={'1':['processing','IndexPage'],'2':['fail','FailPage'],'3':['fail','FailPage'],'4':['success','SuccessPage'],'5':['cancel','CancelPage'],'default':['other','Index'],}/***按钮clickevent*@param{number}status活动状态:1团进行中2团失败3商品售罄4团成功开始5系统取消*/constonButtonClick=(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']]])/***按钮点击事件*@param{number}status活动状态:1开团进行中2开团失败3商品售罄4开团成功5系统取消*/constonButtonClick=(status)=>{letaction=actions.得到(状态)||actions.get('default')sendLog(action[0])jumpTo(action[1])}用es6中的Map对象是不是更好?Map对象和Object对象有什么区别?1、一个对象通常都有自己的原型,所以一个对象总有一个“原型”键。2.对象的键只能是字符串或符号,而Map的键可以是任意值。3、通过size属性可以很容易的得到一个Map的key-value对的个数,而一个object的key-value对的个数只能手动确认。我们需要升级的问题。以前我们只需要判断按钮被点击时的状态,现在我们还需要判断用户的身份:/***buttonclickevent*@param{number}statusActivitystatus:1groupstartinprogress2开团失败3开团成功4商品已售罄5团有货但尚未开团*@param{string}identityIdentity:guestgueststatemastermainstate*/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}}}原谅我没有把每个判断的具体逻辑都写出来,因为代码是t哦冗长。原谅我又用if/else了,因为看到很多人还在用if/else来写这么大的逻辑判断。从上面的例子我们可以看到,当你的逻辑升级为二分判断的时候,你的判断量会翻倍,你的代码量也会翻倍。这时候怎么写得更爽快?constactions=newMap([['guest_1',()=>{/*dosth*/}],['guest_2',()=>{/*dosth*/}],['guest_3',()=>{/*做某事*/}],['guest_4',()=>{/*做某事*/}],['guest_5',()=>{/*做某事*/}],['master_1',()=>{/*做某事*/}],['master_2',()=>{/*做某事*/}],['master_3',()=>{/*做某事*/}],['master_4',()=>{/*做某事*/}],['master_5',()=>{/*做某事*/}],['default',()=>{/*dosth*/}],])/***按钮点击事件*@param{string}identityidentity:guestgueststatemastermainstate*@param{number}statusactivitystatus:1游览进行中2游览失败3游览成功4产品售罄5游览有货但未开启*/constonButtonClick=(identity,status)=>{letaction=actions.get(`${identity}_${status}`)||actions.get('default')action.call(this)}上面代码的核心逻辑是:将两个条件拼接成一个字符串,以拼接后的字符串作为key来处理函数的查找和执行值的映射对象。这种写法在判断多个条件时特别有用。当然,如果上面的代码是用Object对象实现的,也是类似的:constactions={'guest_1':()=>{/*dosth*/},'guest_2':()=>{/*dosth*/},//....}constonButtonClick=(identity,status)=>{让action=actions[`${identity}_${status}`]||actions['default']action.call(this)}如果有同学觉得把查询条件拼写成字符串有点别扭,还有一个解决办法,就是用Map对象,Object对象作为key:constactions=newMap([[{identity:'guest',status:1},()=>{/*dosth*/}],[{identity:'guest',status:2},()=>{/*dosth*/}],//...])constonButtonClick=(identity,status)=>{letaction=[...actions].filter(([key,value])=>(key.identity==identity&&key.status==status))动作。forEach(([key,value])=>value.call(this))}更高级一点吗?Map和Object的区别也可以从这里看出。Map可以使用任何类型的数据作为键。现在让我们稍微升级一下难度。如果guest情况下status1-4的处理逻辑是一样的怎么办,最坏的情况是这样的:constactions=newMap([[{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*/}],//...])更好的写法是缓存处理逻辑函数:constactions=()=>{constfunctionA=()=>{/*dosth*/}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=(身份,状态)=>{让动作=[...actions()]。filter(([key,value])=>(key.identity==identity&&key.status==status))动作。forEach(([key,value])=>value.call(this))}这个已经可以满足日常需求了,但是说真的,上面4次重写functionA还是有点难受。如果判断条件变得特别复杂,比如identity有3个状态,status有10个状态,那么你需要定义30个处理逻辑,而且往往这些逻辑很多都是相同的,这似乎是作者所不希望的接受,所以可以这样实现:constactions=()=>{constfunctionA=()=>{/*dosth*/}constfunctionB=()=>{/*dosth*/}returnnewMap([[/^guest_[1-4]$/,functionA],[/^guest_5$/,functionB],//...])}constonButtonClick=(identity,status)=>{让动作=[...actions()].filter(([key,value])=>(key.test(`${identity}_${status}`)))action.forEach(([key,value])=>value.call(this))}这里Map的优势就更加突出了,可以用正则类型作为key,这样就有了无限可能。如果需求变成,所有的guest情况都要发送一个日志埋点,需要针对不同的状态情况单独进行逻辑处理,那么我们可以这样写:constactions=()=>{constfunctionA=()=>{/*dosth*/}constfunctionB=()=>{/*dosth*/}constfunctionC=()=>{/*发送日志*/}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))}也就是利用数组循环的特点,满足正则条件的所有逻辑都会被执行,那么公共逻辑和个体逻辑就可以同时执行了。因为有规律性的存在,你可以打开你的想象力,解锁更多的玩法。本文不再赘述。综上所述,这篇文章教了你8种写逻辑判断的方法。包括:if/elseswitch一元判断:保存在Object中一元判断:保存在Map中多元判断:将条件拼接成字符串保存在Object中多元判断:将条件拼接成字符串保存在Map中判断时:将条件保存为一个对象并保存在Map中多判断:将条件写成正则表达式保存在Map中至此,本文就告一段落了。愿你以后的生活不只有if/else/switch。