We write js code often encounter complex logic judgment, usually we can use if/else or switch to achieve multiple conditions to judge, but this will have a problem, with the increase in logical complexity, the code if/else/switch will become more and more bloated, more and more unintelligible, so how to more elegantly write the judgment logic, this article takes you to try! This article takes you through the process.
give an example
Let’s start with a snippet of code
/**
*
* @param {number} status
*/
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')
}
}
Through the code you can see the click logic of this button: according to the different activity state to do two things, send logs buried and jump to the corresponding page, you can easily propose a rewrite solution for this code, switch out:
/**
*
* @param {number} status
*/
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')
jumpTo('CancelPage')
break
default:
sendLog('other')
jumpTo('Index')
break
}
}
Well, this looks much clearer than if/else, careful students also found a small trick, case 2 and case 3 logic is the same, you can omit the implementation of the statement and break, the case 2 of the case automatically execute the logic of case 3.
At this point some students will say that there are simpler ways to write:
const actions = {
'1': ['processing','IndexPage'],
'2': ['fail','FailPage'],
'3': ['fail','FailPage'],
'4': ['success','SuccessPage'],
'5': ['cancel','CancelPage'],
'default': ['other','Index'],
}
/**
*
* @param {number}
*/
const onButtonClick = (status)=>{
let action = actions[status] || actions['default'],
logName = action[0],
pageName = action[1]
sendLog(logName)
jumpTo(pageName)
}
The above code does look more refreshing, the cleverness of this approach is: the judgment conditions as the object’s attribute name, the processing logic as the object’s attribute value, when the button is clicked, through the object attribute lookup for the logic of the way to judgment, this way of writing is particularly suitable for the case of a one-dimensional conditional judgment.
Is there another way to write it? There is:
const actions = new Map([
[1, ['processing','IndexPage']],
[2, ['fail','FailPage']],
[3, ['fail','FailPage']],
[4, ['success','SuccessPage']],
[5, ['cancel','CancelPage']],
['default', ['other','Index']]
])
/**
*
* @param {number} status
*/
const onButtonClick = (status)=>{
let action = actions.get(status) || actions.get('default')
sendLog(action[0])
jumpTo(action[1])
}
This write used in es6 Map object, is not more cool.Map object and Object object what is the difference?
An object usually has its own prototype, so an object always has a “prototype” key.
An object’s keys can only be strings or Symbols, but a Map’s keys can be any value.
You can easily get the number of key-value pairs of a Map through the size attribute, while the number of key-value pairs of an object can only be confirmed manually.
We need to escalate the problem a bit, before we only needed to determine STATUS when the button was clicked, now we also need to determine the identity of the user:
/**
*
* @param {number} status
* @param {string} identity
*/
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
}
}
}
Forgive me if I don’t write the exact logic in each judgment, because the code is too lengthy.
Forgive me for using if/else again, because I see a lot of people still writing these big logical judgments in if/else.
As we can see from the example above, when your logic is upgraded to binary judgments, you double the amount of judgments and you double the amount of code, so how can you write it more refreshingly?
const actions = new Map([
['guest_1', ()=>{/*do sth*/}],
['guest_2', ()=>{/*do sth*/}],
['guest_3', ()=>{/*do sth*/}],
['guest_4', ()=>{/*do sth*/}],
['guest_5', ()=>{/*do sth*/}],
['master_1', ()=>{/*do sth*/}],
['master_2', ()=>{/*do sth*/}],
['master_3', ()=>{/*do sth*/}],
['master_4', ()=>{/*do sth*/}],
['master_5', ()=>{/*do sth*/}],
['default', ()=>{/*do sth*/}],
])
/**
*
* @param {string} identity
* @param {number} status
*/
const onButtonClick = (identity,status)=>{
let action = actions.get(`${identity}_${status}`) || actions.get('default')
action.call(this)
}
The core logic of the above code is: the two conditions are spliced into a string, and through the conditions of the spliced string as the key to the processing function as the value of the Map object to find and execute, this writing is especially good in the multi-conditional judgment time.
Of course the above code would be similar if implemented with Object objects:
const actions = {
'guest_1':()=>{/*do sth*/},
'guest_2':()=>{/*do sth*/},
//....
}
const onButtonClick = (identity,status)=>{
let action = actions[`${identity}_${status}`] || actions['default']
action.call(this)
}
If some students feel that the query conditions are spelled out as a string is a bit awkward, then there is another option, is to use Map objects, with Object objects as the key:
const actions = new Map([
[{identity:'guest',status:1},()=>{/*do sth*/}],
[{identity:'guest',status:2},()=>{/*do sth*/}],
//...
])
const onButtonClick = (identity,status)=>{
let action = [...actions].filter(([key,value])=>(key.identity == identity && key.status == status))
action.forEach(([key,value])=>value.call(this))
}
Isn’t it a little bit more advanced?
The difference between Map and Object is also seen here, Map can use any type of data as key.
Let’s now escalate the difficulty a little bit more, what if the GUEST case has the same processing logic for STATUS 1-4, worst case:
const actions = 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 */}],
//...
])
A better way to write this is to cache the processing logic functions:
const actions = ()=>{
const functionA = ()=>{/*do sth*/}
const functionB = ()=>{/*do sth*/}
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))
}
This has been written to meet the daily needs, but seriously, the above rewrite 4 times functionA or a little upset, if the judgment conditions become particularly complex, such as identity has 3 kinds of status, status has 10 kinds of status, then you need to define 30 processing logic, and often a lot of these logics are the same, which seems to be the author does not want to accept, but it can be implemented this way. It can be realized like this.
const actions = ()=>{
const functionA = ()=>{/*do sth*/}
const functionB = ()=>{/*do sth*/}
return new Map([
[/^guest_[1-4]$/,functionA],
[/^guest_5$/,functionB],
//...
])
}
const onButtonClick = (identity,status)=>{
let action = [...actions()].filter(([key,value])=>(key.test(`${identity}_${status}`)))
action.forEach(([key,value])=>value.call(this))
}
Here the advantage of Map is more prominent, you can use the regular type as the key, so there are infinite possibilities, if the demand becomes, where the guest case to send a log buried, different status cases also need to be dealt with in a separate logic, then we can write:.
const actions = ()=>{
const functionA = ()=>{/*do sth*/}
const functionB = ()=>{/*do sth*/}
const functionC = ()=>{/*send log*/}
return new Map([
[/^guest_[1-4]$/,functionA],
[/^guest_5$/,functionB],
[/^guest_.*$/,functionC],
//...
])
}
const onButtonClick = (identity,status)=>{
let action = [...actions()].filter(([key,value])=>(key.test(`${identity}_${status}`)))
action.forEach(([key,value])=>value.call(this))
}
That is to say, using the characteristics of the array loop, the logic that meets the conditions of the regular will be executed, then you can simultaneously execute the public logic and separate logic, because of the existence of the regular, you can open the imagination to unlock more ways to play, this article will not go into details.
This article has taught you 8 ways to write logical judgments, including:
- if/else
- switch
- When judging monadically: save to Object
- When judging monadically: save to Map
For multivariate judgment: splice the condition into a string and store it in the Object.
Multiple judgment: splice the condition into a string and store it in a Map.
Multiple judgment: store condition as Object in Map.
For multivariate judgments: store the condition writing rule in the Map.
At this point, this article will also come to an end, may you have more than just if/else/switch in your future life.