Home  >  Article  >  Web Front-end  >  Elegant way to write complex judgments in JavaScript

Elegant way to write complex judgments in JavaScript

hzc
hzcforward
2020-06-16 09:51:151880browse

Premise


We often encounter complex logical judgments when writing js code. Usually you can use if/else or switch to implement multiple conditional judgments, but There will be a problem with this. As the logic complexity increases, the if/else/switch in the code will become more and more bloated and difficult to understand. So how to write judgment logic more elegantly? This article will give you a try one time.

For example

Look at a piece of code first

/**
 * 按钮点击事件
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
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')
  }
}

You can see the click logic of this button through the code: do two things according to different activity states, send logs to bury points and jump to the corresponding page. You can easily propose a rewriting plan for this code. The switch appears:

/**
 * 按钮点击事件
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
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 discovered the small Tip, when the logic of case 2 and case 3 is the same, you can omit the execution statement and break, and the logic of case 3 will be automatically executed in case 2.

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

const actions = {
  '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 系统取消
 */
const onButtonClick = (status)=>{
  let action = actions[status] || actions['default'],
      logName = action[0],
      pageName = action[1]
  sendLog(logName)
  jumpTo(pageName)
}

The above code does look cleaner. The smart thing about this method is that it takes the judgment condition as an object The attribute name uses the processing logic as the attribute value of the object. When the button is clicked, logical judgment is made by searching the object attributes. This writing method is particularly suitable for unary conditional judgment.

Is there any other 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']]
])
/**
 * 按钮点击事件
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 商品售罄 4 开团成功 5 系统取消
 */
const onButtonClick = (status)=>{
  let action = actions.get(status) || actions.get('default')
  sendLog(action[0])
  jumpTo(action[1])
}

Writing like this uses the Map object in es6. Isn’t it more fun? What is the difference between Map object and Object object?

  1. An object usually has its own prototype, so an object always has a "prototype" key.

  2. The key of an object can only be a string or Symbols, but the key of a Map can be any value.

  3. 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 upgrade the problem. In the past, we only needed to judge the status when clicking the button. Now we also need to judge the user’s identity:

/**
 * 按钮点击事件
 * @param {number} status 活动状态:1开团进行中 2开团失败 3 开团成功 4 商品售罄 5 有库存未开团
 * @param {string} identity 身份标识: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
    }
  }
}

Forgive me for not writing every judgment. The specific logic here is because the code is too lengthy.

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

We can see from the above example that when your logic is upgraded to binary judgment, your judgment amount will double, and your code amount will also double. How to 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*/}],
])

/**
 * 按钮点击事件
 * @param {string} identity 身份标识:guest客态 master主态
 * @param {number} status 活动状态:1 开团进行中 2 开团失败 3 开团成功 4 商品售罄 5 有库存未开团
 */
const onButtonClick = (identity,status)=>{
  let action = actions.get(`${identity}_${status}`) || actions.get('default')
  action.call(this)
}

The core logic of the above code is: splice the two conditions into a string, and search and execute the Map object using the conditional string as the key and the processing function as the value. This writing method is used in multiple It is especially useful when making conditional judgments.

Of course, the above code is similar if it is implemented using 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 it is a bit awkward to spell the query conditions into strings, then there is another solution, which is to use Map objects. , using the Object object 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))
}

Is it a little more advanced?

The difference between Map and Object can also be seen here. Map can use any type of data as key.

Now we will upgrade the difficulty a little bit. What if the processing logic of status1-4 is the same in the guest case. 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 */}],
  //...
])

A better way to write it is Cache the processing logic function

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))
}

Writing like this can already meet daily needs, but to be serious, it is still a bit uncomfortable to rewrite functionA 4 times above. If the judgment condition becomes particularly complicated, for example, identity has 3 There are 10 states in status. Then you need to define 30 processing logics, and often many of these logics are the same. This seems to be something I don’t want to accept. 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])=>(key.test(`${identity}_${status}`)))
  action.forEach(([key,value])=>value.call(this))
}

Here The advantages of Map are even more prominent. Regular types can be used as keys, which opens up unlimited possibilities. If the requirement becomes that a log burying point must be sent for all guest situations, and different status situations also require separate logical processing, then we can Write like 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])=>(key.test(`${identity}_${status}`)))
  action.forEach(([key,value])=>value.call(this))
}

That is to say, using the characteristics of array loops, logic that meets the regular conditions will be executed. Then public logic and individual logic can be executed at the same time. Because of the existence of regular rules, you can open your imagination and unlock it. There are more ways to play, which I won’t go into details in this article.

Summary

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

  1. if/else

  2. switch

  3. When making one-yuan judgment: Save it in Object

  4. When making one-way judgment: Save it in Map

  5. When making multiple judgments: Splice the condition into a string and save it in Object

  6. When making multiple judgments: Splice the condition into a string and save it in Map

  7. When making multiple judgments: Save the condition as an Object and save it in the Map

  8. When making multiple judgments: Save the condition as a regular expression in the Map

At this point, this article will come to an end. I hope that your future life will not only have if/else/switch.

Recommended tutorial: "JS Tutorial"

The above is the detailed content of Elegant way to write complex judgments in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete