When we write JS code, we often encounter complex logic judgment, usually we can use if/else or switch to achieve multiple conditional judgment, but this will have a problem, with the increase of logic complexity, the code of if/else/switch 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. Let’s take a look at some code
@param {number} status Active status: */const onButtonClick = (status)=>{if(status == 1){sendLog('processing') jumpTo('IndexPage') }elseif(status == 2){ sendLog('fail') jumpTo('FailPage') }elseif(status == 3){ sendLog('fail') jumpTo('FailPage') }elseif(status == 4){ sendLog('success') jumpTo('SuccessPage') }elseif(status == 5){ sendLog('cancel') jumpTo('CancelPage') }else { sendLog('other') jumpTo('Index') } }Copy the code
You can see the clicking logic of this button in the code: do two things according to the different activity state, send the log burying point and jump to the corresponding page, you can easily put forward the rewriting scheme of this code, switch appears:
@param {number} status Active status: */const onButtonClick = (status)=>{switch (status){case1: sendLog('processing') jumpTo('IndexPage') breakcase2: case3: sendLog('fail') jumpTo('FailPage') breakcase4: sendLog('success') jumpTo('SuccessPage') breakcase5: sendLog('cancel') jumpTo('CancelPage') breakdefault: sendLog('other') jumpTo('Index') break } }Copy the code
If the logic in case 2 is the same as that in case 3, you can dispense with the execution of the statement and break, and the logic in case 2 is automatically executed in case 3. There is also 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'],} /** * button click event * @param {number} status Active: 1 open group on 2 failure 3 goods sold out 4 open groups successfully cancel * / 5 system 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 method is that the judgment condition is used as the attribute name of the object, the processing logic is used as the attribute value of the object, and when the button is clicked, the logic is determined by the object attribute lookup. This writing method is particularly suitable for unary condition judgment. Is there another way to write it? Some:
const actions = newMap([ [1, ['processing','IndexPage']], [2, ['fail','FailPage']], [3, ['fail','FailPage']], [4, ['success','SuccessPage']], [5, ['cancel','CancelPage']], ['default', ['other','Index']]]) /** * @param {number} status 1 open group on 2 failure 3 goods sold out 4 open groups successfully cancel * / 5 system const onButtonClick = (status) = > {let action = actions. Get (status) | | actions.get('default') sendLog(action[0]) jumpTo(action[1]) }Copy the code
Is it better to use the Map object in ES6? What is the difference between a Map Object and an Object Object? An object usually has its own prototype, so an object always has a “prototype” key. The keys of an object can only be strings or Symbols, but the keys of a Map can be any value. You can easily get the number of key-value pairs for a Map using the size attribute, whereas the number of key-value pairs for an object can only be determined manually. We need to upgrade the problem. Before the button click only needed to determine the status, now also need to determine the user’s identity:
@param {number} status Active status: 1 in progress 2 in failure 3 in success 4 Sold out 5 In stock * @param {string} identity: */const onButtonClick = (status,identity)=>{if(identity == 'guest'){if(status == 1){//do STH }elseif(status == 2){ //do sth }elseif(status == 3){ //do sth }elseif(status == 4){ //do sth }elseif(status == 5){ //do sth }else { //do sth } }elseif(identity == 'master') { if(status == 1){ //do sth }elseif(status == 2){ //do sth }elseif(status == 3){ //do sth }elseif(status == 4){ //do sth }elseif(status == 5){ //do sth }else { //do sth } } }Copy the code
Forgive me for not writing the specific logic of each judgment, because the code is too long. Forgive me for using if/else again, because I see a lot of people still using if/else to write long logical judgments. As we can see from the above example, when you upgrade your logic to binary judgment, you double the amount of judgment, and you double the amount of code, so how can you write cleaner?
const actions = newMap([ ['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 button click event {string} identity identification: @param {number} status Active status: */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: concatenate two conditions into a string, and search and execute the Map object with the conditional concatenation string as the key and the processing function as the value. This writing method is especially useful for multivariate condition judgment. Of course, the above code is similar if the Object is implemented:
const actions = {
'guest_1':()=>{/*do sth*/},
'guest_2':()=>{/*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 a bit awkward to spell the query criteria as strings, there is an alternative: use a Map Object with an Object as key:
const actions = newMap([ [{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 it a little more advanced? A Map can use any type of data as a key. If status1-4 is the same as status1-4, then status1-4 is the same as status1-4.
const actions = newMap([ [{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 function:
const actions = ()=>{ const functionA = ()=>{/*do sth*/} const functionB = ()=>{/*do sth*/} returnnewMap([ [{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
This is good enough for everyday use, but seriously, rewriting functionA four times is a bit uncomfortable. If the criteria get really complicated, for example identity has 3 states, status has 10 states, then you need to define 30 processing logic, many of which are the same. This seems to be what the author does not want to accept, which can be achieved as follows:
const actions = ()=>{ const functionA = ()=>{/*do sth*/} const functionB = ()=>{/*do sth*/} returnnewMap([ [/^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
We can use the regex type as the key, which opens up a lot of possibilities. If the requirement is to send a log burying point for all guest cases and separate logic for different status cases, we can write:
const actions = ()=>{
const functionA = ()=>{/*do sth*/}
const functionB = ()=>{/*do sth*/}
const functionC = ()=>{/*send log*/}
returnnewMap([
[/^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
That is to say, using the nature of the array loop, any logic that meets the re condition will be executed, so you can execute both the public logic and the separate logic at the same time. Because of the re, you can open your imagination to unlock more gameplay, which I won’t go into here. conclusion
If /else switch unary condition: Store in Object unary condition: Store in Map multiple condition: Concatenate condition into a string and store in Object multiple condition: Condition (Object) : condition (regular) : Condition (Object) : Condition (regular) : Map (Object) : Condition (regular) : Map (Object) : Condition (regular) : Map
Reprint wechat public number programmer Black uncle