SoFunction
Updated on 2025-03-10

Detailed explanation of more elegant writing code for JS complex judgment

When writing JS code, we often encounter complex logical judgments. Usually, if/else or switch can be used to achieve multiple conditional judgments, but this will cause a problem. As the logic complexity increases, if/else/switch in the code will become more and more bloated and less understandable. So how to write judgment logic more elegantly, this article will give you a try.

Give an example

Let's look at a piece of code first

/**
  * Button click event
  * @param {number} status Activity status: 1 The group is in progress 2 The group is failed 3 The product is sold out 4 The group is successful 5 The system is cancelled
  */
const onButtonClick1 = (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: do two things according to different activity status, send logs to bury points and jump to the corresponding page. You can easily propose a rewrite plan for this code, and switch appears:

/**
  * Button click event
  * @param {number} status Activity status: 1 The group is in progress 2 The group is failed 3 The product is sold out 4 The group is successful 5 The system is cancelled
  */
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 have also discovered small tricks. When case 2 and case 3 logic are the same, they can omit execution statements and breaks, and then case 2 situation automatically executes the logic of case 3.

At this time, some students would say that there is a simpler way to write it:

const actions = {
 '1': ['processing','IndexPage'],
 '2': ['fail','FailPage'],
 '3': ['fail','FailPage'],
 '4': ['success','SuccessPage'],
 '5': ['cancel','CancelPage'],
 'default': ['other','Index'],
}
/**
  * Button click event
  * @param {number} status Activity status: 1 group opening is in progress 2 group opening failed 3 product sold out 4 group opening successful 5 system cancellation
  */
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 method is: use the judgment condition as the object's attribute name, and use the processing logic as the object's attribute value. When the button is clicked, logical judgment is made through the object's attribute search. This writing method is particularly suitable for the case of single-variate condition judgment.

Are there any other ways to write it? some:

const actions = new Map([
 [1, ['processing','IndexPage']],
 [2, ['fail','FailPage']],
 [3, ['fail','FailPage']],
 [4, ['success','SuccessPage']],
 [5, ['cancel','CancelPage']],
 ['default', ['other','Index']]
])
/**
  * Button click event
  * @param {number} status Activity status: 1 The group is in progress 2 The group is failed 3 The product is sold out 4 The group is successful 5 The system is cancelled
  */
const onButtonClick = (status)=>{
 let action = (status) || ('default')
 sendLog(action[0])
 jumpTo(action[1])
}

Isn't it more exciting to write this way when using the Map object in es6? What is the difference between Map objects and Object objects?

An object usually has its own prototype, so an object always has a "prototype" key.
An object's key can only be strings or Symbols, but a Map's key can be any value.

You can easily get the number of key-value pairs of a Map through the size property, while the number of key-value pairs of an object can only be manually confirmed.

We need to upgrade the problem. In the past, when the button was clicked, we only needed to judge the status, but now we need to judge the user's identity:

/**
  * Button click event
  * @param {number} status Activity status: 1 group opening is in progress 2 group opening failed 3 group opening successful 4 product sold out 5 group opening in stock
  * @param {string} identity identity: guest master main
  */
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 for not writing the specific logic in each judgment because the code is too verbose.

Forgive me for using if/else again, because I see many people still use if/else to write such large logical judgments.

From the above example, we can see that when your logic is upgraded to binary judgment, your judgment amount will double, and your code amount will also double. How can you write more refreshingly at this time?

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*/}],
])

/**
  * Button click event
  * @param {string} identity identity: guest master main
  * @param {number} status Activity status: 1 The group is in progress 2 The group is failed 3 The group is successful 4 The product is sold out 5 The group is not opened in stock
  */
const onButtonClick = (identity,status)=>{
 let action = (`${identity}_${status}`) || ('default')
 (this)
}

The core logic of the above code is: splice two conditions into strings, and search and execute Map objects with processing functions as values ​​by splicing the strings as keys. This writing method is especially useful when judging multiple conditions.

Of course, the above code is similar if it is implemented using an Object object:

const actions = {
 'guest_1':()=>{/*do sth*/},
 'guest_2':()=>{/*do sth*/},
 //....
}
const onButtonClick = (identity,status)=>{
 let action = actions[`${identity}_${status}`] || actions['default']
 (this)
}

If some students find it a bit awkward to spell query conditions into strings, then there is another solution, which is to use Map objects and Object objects as keys

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])=>( == identity &&  == status))
 (([key,value])=>(this))
}

Is it a little more advanced?

Here we also see the difference between Map and Object. Map can use any type of data as key.

Let's upgrade the difficulty a little more now. What if the processing logic of status1-4 is the same in the guest case? The worst case is:

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 it is to cache 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])=>( == identity &&  == status))
 (([key,value])=>(this))
}

This writing can meet daily needs, but to be serious, it is still a bit unhappy to rewritten functionA 4 times above. If the judgment conditions become particularly complex, such as identity has 3 states and status has 10 states, then you need to define 30 processing logics, and often many of these logics are the same, which seems to be something that the author does not want to accept, so it can be implemented 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])=>((`${identity}_${status}`)))
 (([key,value])=>(this))
}

The advantages of Map are more prominent here. You can use regular types as keys, so there are infinite possibilities. If the requirement becomes, a log burial point must be sent for any guest situation, and different status situations also require separate logical processing. Then we can write this:

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])=>((`${identity}_${status}`)))
 (([key,value])=>(this))
}

In other words, using the characteristics of array loops, logic that meets regular conditions will be executed, so that public logic and separate logic can be executed at the same time. Because of the existence of regularity, you can open your imagination to unlock more gameplay, which will not be described in this article.

Summarize

The above is a detailed explanation of the more elegant writing code for JS complex judgments introduced to you. I hope it will be helpful to you. If you have any questions, please leave me a message and the editor will reply to you in time. Thank you very much for your support for my website!