JS逻辑判断不要只知道⽤if-else和switch条件判断(⼩技
巧)
我们在编写 JS 代码时,经常会遇到逻辑判断复杂的情况。⼀般情况下,可以⽤ if/else 或 switch 来实现多个条件判断,但会出现⼀个问题:随着逻辑复杂度的增加,代码中的 if/else 和 switch 会越来越臃肿。本⽂将带你尝试写出更优雅的判断逻辑。
⽐如说下⾯这样⼀段代码:
const onButtonClick = (status) => {
if (status == 1) {
sendLog('processing')
jumpTo('IndexPage')
} else if (status == 2) {
sendLog('fail')
jumpTo('FailPage')
} else if (status == 3) {
sendLog('fail')
jumpTo('FailPage')
} else if (status == 4) {
sendLog('success')
jumpTo('SuccessPage')
} else if (status == 5) {
sendLog('cancel')
jumpTo('CancelPage')
} else {
sendLog('other')
jumpTo('Index')
}
}
你可以在代码中看到这个按钮的点击逻辑。根据活动状态的不同做两件事,发送⽇志埋点并跳转到相应的页⾯。很容易想到这段代码可以⽤ switch 重写如下:
const onButtonClick = (status) => {
switch (status) {
case 1:
sendLog('processing')
jumpTo('IndexPage')
break
case 2:
case 3:
sendLog('fail')
jumpTo('FailPage')
break
case 4:
sendLog('success')
jumpTo('SuccessPage')
break
case 5:
sendLog('cancel')
switch case判断字符串
jumpTo('CancelPage')
break
default:
sendLog('other')
jumpTo('Index')
break
}
}
好吧,看起来⽐ if/else 层次结构更清晰⼀些,细⼼的读者可能也发现了⼀个⼩窍门:case 2 和 case 3 的逻辑⼀样时,可以把前⾯的逻辑处理代码省略,case 2 会⾃动执⾏与 case 3 的逻辑。
不过,还有⼀个更简单的写法:
const actions = {
'1': ['processing', 'IndexPage'],
'2': ['fail', 'FailPage'],
'3': ['fail', 'FailPage'],
'4': ['success', 'SuccessPage'],
'5': ['cancel', 'CancelPage'],
default: ['other', 'Index'],
}
const onButtonClick = (status) => {
let action = actions[status] || actions['default'],
logName = action[0],
pageName = action[1]
sendLog(logName)
jumpTo(pageName)
}
上⾯的代码看起来确实⽐较⼲净,这种⽅法的巧妙之处在于,它把判断条件作为对象的属性名,把处理逻辑作为对象的属性值。在点击按钮的时候,这种⽅法特别适⽤于单项条件判断的情况,即通过对象属性查的⽅式进⾏逻辑判断。
这个⽅法很好,但是有没有其他的⽅法来编码呢?有的!
const actions = new Map([
[1, ['processing', 'IndexPage']],
[2, ['fail', 'FailPage']],
[3, ['fail', 'FailPage']],
[4, ['success', 'SuccessPage']],
[5, ['cancel', 'CancelPage']],
['default', ['other', 'Index']],
])
const onButtonClick = (status) => {
let action = (status) || ('default')
sendLog(action[0])
jumpTo(action[1])
}
使⽤ Map 代替 Object 有很多优点,Map 对象和普通对象有的区别是:
⼀个对象通常有⾃⼰的原型,所以⼀个对象总是有⼀个“prototype”键
对象的键只能是⼀个字符串或符号,但 Map 的键可以是任何值
你可以通过使⽤ size 属性很容易得到 Map 中的键值对的数量,⽽⼀个对象中的键值对数量不能直接获取
现在我们来升级⼀下这个问题的难度。点击按钮时,不仅要判断状态,还要判断⽤户的⾝份。
const onButtonClick = (status, identity) => {
if (identity == 'guest') {
if (status == 1) {
//do sth
} else if (status == 2) {
//do sth
} else if (status == 3) {
//do sth
} else if (status == 4) {
//do sth
} else if (status == 5) {
//do sth
} else {
//do sth
}
} else if (identity == 'master') {
if (status == 1) {
//do sth
} else if (status == 2) {
//do sth
} else if (status == 3) {
//do sth
} else if (status == 4) {
//do sth
} else if (status == 5) {
//do sth
} else {
//do sth
}
}
}
从上⾯的例⼦中可以看到,当你的逻辑升级到双重判断的时候,你的判断⼒就会加倍,你的代码就会加倍。
如何才能让代码更⼲净利落呢?
这⾥有⼀个解决⽅案。
const actions = new Map([
['guest_1', () => {}],
['guest_2', () => {}],
['guest_3', () => {}],
['guest_4', () => {}],
['guest_5', () => {}],
['master_1', () => {}],
['master_2', () => {}],
['master_3', () => {}],
['master_4', () => {}],
['master_5', () => {}],
['default', () => {}],
])
const onButtonClick = (identity, status) => {
let action = (`${identity}_${status}`) || ('default')
action.call(this)
}
上述代码的核⼼逻辑是。将两个判断条件拼接成⼀个字符串作为 Map 的键,然后在查询时直接查询对应字符串的值。当然,我们也可以在这⾥把 Map 改成 Object。
const actions = {
guest_1: () => {},
guest_2: () => {},
//....
}
const onButtonClick = (identity, status) => {
let action = actions[`${identity}_${status}`] || actions['default']
action.call(this)
}
如果读者觉得把查询拼成⼀个字符串有点尴尬,还有另⼀个解决办法,那就是⽤⼀个 Map 对象作为 key。
const actions = new Map([
[{ identity: 'guest', status: 1 }, () => {}],
[{ identity: 'guest', status: 2 }, () => {}],
//...
])
const onButtonClick = (identity, status) => {
let action = [...actions].filter(([key, value]) => key.identity == identity && key.status == status)
action.forEach(([key, value]) => value.call(this))
}
这⾥你也可以看到 Map 和普通对象的区别,其中 Map 可以⽤任何类型的数据作为键。现在让我们把它的难度再提⾼⼀点。如果对于 guest ⾝份来说,状态 1-4 的处理逻辑是⼀样的呢?
最坏的情况是这样的(代码⼤量重复):
const actions = new Map([
[{ identity: 'guest', status: 1 }, () => {}],
[{ identity: 'guest', status: 2 }, () => {}],
[{ identity: 'guest', status: 3 }, () => {}],
[{ identity: 'guest', status: 4 }, () => {}],
[{ identity: 'guest', status: 5 }, () => {}],
//...
])
更好的⽅法是把处理逻辑函数分离出来:
const actions = () => {
const functionA = () => {}
const functionB = () => {}
return new Map([
[{ 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],
//...
])
}
const onButtonClick = (identity, status) => {
let action = [...actions()].filter(([key, value]) => key.identity == identity && key.status == status)
action.forEach(([key, value]) => value.call(this))
}
这对于⽇常需求来说已经⾜够了,但是说真的,函数 A 被引⽤了 4 次,还是有点烦⼈。
如果事情真的变得很复杂,⽐如⾝份有 3 种,状态有 10 种,你需要定义 30 个处理逻辑,其中很多处理逻辑都是⼀样的,这似乎让⼈⽆法接受。
⽽你可以这样做:
const actions = () => {
const functionA = () => {} // 逻辑处理 A
const functionB = () => {} // 逻辑处理 B
return new Map([
[/^guest_[1-4]$/, functionA],
[/^guest_5$/, functionB],
//...
])
}
const onButtonClick = (identity, status) => {
let action = [...actions()].filter(([key, value]) => st(`${identity}_${status}`))
action.forEach(([key, value]) => value.call(this))
}
这时使⽤ Map ⽽不是 Object 的优势⽐较明显,因为可以⽤正则式作为键。
如果需求变成:所有的对 guest 操作都需要发送⼀个⽇志埋点,不同状态的 guest 可能有不同的逻辑处理,那么我们可以写成如下:
const actions = () => {
const functionA = () => {} // 逻辑处理 A
const functionB = () => {} // 逻辑处理 B
const functionC = () => {} // 发送⽇志 C
return new Map([
[/^guest_[1-4]$/, functionA],
[/^guest_5$/, functionB],
[/^guest_.*$/, functionC],
//...
])
}
const onButtonClick = (identity, status) => {
let action = [...actions()].filter(([key, value]) => st(`${identity}_${status}`))
action.forEach(([key, value]) => value.call(this))
}
这样⼀来,公共逻辑和单个逻辑可以同时执⾏。
总结
本⽂讲到了⼋种 JS 逻辑判断的写法,包括:
1. if/else
2. switch
3. 单⼀判断:存储在 Object 中
4. 单⼀判断:存储在 Map 对象中
5. 多重判断:将条件串联成⼀个字符串,存储在 Object 中
6. 多重判断:将条件连成⼀个字符串,存储在 Map 对象中
7. 多重判断:把条件作为对象存储在 Map 中
8. 多重判断:把条件写成正则式存储在 Map 中
到此这篇关于JS 逻辑判断不要只知道⽤ if-else 和 switch条件判断的⽂章就介绍到这了,更多相关js 逻辑判断if else switch内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论