The premise

When we write JAVASCRIPT code, we often encounter complex logic judgment, usually you can use if/else or switch to achieve multiple conditions, but this will have a problem, as the logic complexity increases, if/else/switch code will become more and more bloated, more and more difficult to understand, So how to write more elegant judgment logic, this article takes you to try.

For example

Let’s start with a piece of code

/** * Button click event * @param {number} status Active status: 1 In progress 2 Failed 3 Sold out 4 successful 5 System cancelled */
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')}}Copy the code

You can see the click logic of this button: according to the different activity state to do two things, send the log buried point and jump to the corresponding page, you can easily put forward this code rewrite scheme, switch out:

/** * Button click event * @param {number} status Active status: 1 In progress 2 Failed 3 Sold out 4 successful 5 System 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}}Copy the code

Well, this looks a lot clearer than if/else, and you noticed the trick, if case 2 and Case 3 have the same logic, you can skip the statement and break, so case 2 automatically executes case 3 logic.

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 Active status: 1 In progress 2 Failed 3 Sold out 4 successful 5 System cancelled */
const onButtonClick = (status) = >{
  let action = actions[status] || actions['default'],
      logName = action[0],
      pageName = action[1]
  sendLog(logName)
  jumpTo(pageName)
}
Copy the code

The above code does look cleaner. The clever thing about this approach is that it uses the condition as the property name of the object, the processing logic as the property value of the object, and makes the logical judgment by looking up the property of the object when the button is clicked.

Is there another way 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 Active status: 1 In progress 2 Failed 3 Sold out 4 successful 5 System cancelled */
const onButtonClick = (status) = >{
  let action = actions.get(status) || actions.get('default')
  sendLog(action[0])
  jumpTo(action[1])}Copy the code

Is it even more fun to write this using es6 Map objects? What’s the difference between a Map Object and an Object?

  1. An object usually has its own prototype, so an object always has a “prototype” key.
  2. An object’s key can only be a string or Symbols, but a Map’s key can be any value.
  3. You can easily get the number of key pairs in a Map using the size property, whereas the number of key pairs in an object can only be manually determined.

We need to upgrade the problem. Instead of just determining status when a button is clicked, we now need to determine the identity of the user:

@param {number} status @param {number} status @param {number} status @param {number} status @param {number} status @param {number} status @param {number} status Guest Master */
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}}}Copy the code

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 a lot of people still using if/else to write big chunks of logic.

As we can see from the above example, when you upgrade your logic to binary judgments, you double the amount of judgments and your code doubles, so how do you write cleaner?

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 {number} status * @param {number} status * @param {number} status 1 Group opening in progress 2 group opening failure 3 group opening success 4 Goods sold out 5 inventory not opened */
const onButtonClick = (identity,status) = >{
  let action = actions.get(`${identity}_${status}`) || actions.get('default')
  action.call(this)}Copy the code

The core logic of the above code is to concatenate two conditions into a string and find and execute a Map object with the conditional concatenation string as the key and the processing function as the value. This is especially useful when using multiple conditions.

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

const actions = {
  'guest_1':(a)= >{/*do sth*/},
  'guest_2':(a)= >{/*do sth*/},
  //....
}

const onButtonClick = (identity,status) = >{
  let action = actions[`${identity}_${status}`] || actions['default']
  action.call(this)}Copy the code

For those of you who find it awkward to spell the query as a string, there is an alternative: Map, Object as 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))}Copy the code

Is that a little more advanced?

A Map can use any type of data as a key.

Let’s now escalate the difficulty a little bit, what if status1-4 handles the same logic in guest cases, the worst case is this:

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 */}]./ /...
])
Copy the code

A better way to write this is to cache the processing logic functions:

const actions = (a)= >{
  const functionA = (a)= >{/*do sth*/}
  const functionB = (a)= >{/*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))}Copy the code

If the criteria become too complex, for example, identity has three states and status has ten, then you need to define 30 pieces of logic, many of which are the same. This seems to be something I don’t want to accept, but it can be done like this:

const actions = (a)= >{
  const functionA = (a)= >{/*do sth*/}
  const functionB = (a)= >{/*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))}Copy the code

If the requirement is to send a log buried point for all guest cases and separate logic processing for different status cases, then we can write:

const actions = (a)= >{
  const functionA = (a)= >{/*do sth*/}
  const functionB = (a)= >{/*do sth*/}
  const functionC = (a)= >{/*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))}Copy the code

In other words, using the array loop feature, you can execute both common logic and individual logic at the same time. Because of the presence of the regex, you can open your imagination to unlock more gameplay, which will not be covered in this article.

conclusion

This article has taught you eight ways to write logical judgments, including:

  1. if/else
  2. switch
  3. Unary judgment: save to Object
  4. Unary judgment: stored in the Map
  5. In multivariate judgment, condition is concatenated into a string and stored in Object
  6. For multivariate judgment: The condition is spliced into a string and stored in the Map
  7. For multivariate judgment: Store the condition as Object in the Map
  8. For multivariate judgment: Save condition as regular in Map

And that brings this article to a close. May your future life be more than just if/else/switch.

If you are interested in this article, please follow the author’s wechat official account: “Daxiyifang FE”