The world is so big and there are so many attractions. Sometimes, in a different way, in a different Angle, in a different company, there will be different feelings and harvest. The same goes for writing code.

1. Introduction

I believe many people have such experience, when the project is relatively busy, they always consider the implementation of the first, with the best way to realize the project, when the project is not busy, look at the previous code, think of a better implementation scheme, or optimization scheme. I am no exception. Here are my recent solutions to replace if-else and switch in specific situations. If you have any ideas, please leave them in the comments section.

2. Replace if-else with look-up table

For example, you may encounter requirements similar to the following: For example, a platform credit score rating over 700-950 means excellent credit, 650-700 excellent credit, 600-650 good credit, 550-600 medium credit, and 350-550 poor credit.

The implementation is very simple

function showGrace(grace) {
    let _level=' ';
    if(grace>=700){
        _level='Excellent credit'
    }
    else if(grace>=650){
        _level='Excellent credit'
    }
    else if(grace>=600){
        _level='Good credit'
    }
    else if(grace>=550){
        _level='Medium credit'
    }
    else{
        _level='Poor credit'
    }
    return _level;
}
Copy the code

It works fine, but there are problems

1. In case of future demand, for example, 650-750 means excellent credit, and 750-950 means excellent credit. So the whole approach has to change.

2. There are various fairy numbers in the method: 700,650,600,550. Future maintenance may be problematic.

3. Too much if-else, seems a little obsessive

Therefore, the look-up table is used to separate the configuration data from the business logic

function showGrace(grace) {
    letGraceForLevel = [700650600550];let levelText=['Excellent credit'.'Excellent credit'.'Good credit'.'Medium credit'.'Poor credit'];
    for(leti=0; i<graceForLevel.length; i++){if(grace>=graceForLevel[i]){
            returnlevelText[i]; }} // If it does not exist, then the score is very low and the last one is returnedreturn levelText[levelText.length-1];
}
Copy the code

The advantage of this change is that if you need to change it, you only need to change graceForLevel, levelText. The business logic does not need to change.

Why is separation of data placement and business logic recommended here

1. Modifying configuration data is less costly and risky than modifying service logic

2. The source and modification of configuration data can be flexible

3. The recommendation configuration is separated from the business logic, so that the code that needs to be modified can be found more quickly

If you want to be more flexible, you can encapsulate a slightly more generic look-up function.

function showGrace(grace,level,levelForGrace) {
    for(leti=0; i<level.length; i++){if(grace>=level[i]){
            returnlevelForGrace[i]; }} // If it does not exist, then the score is very low and the last one is returnedreturn levelForGrace[levelForGrace.length-1];
}
letGraceForLevel = [700650600550];let levelText=['Excellent credit'.'Excellent credit'.'Good credit'.'Medium credit'.'Poor credit'];
Copy the code

There is another benefit to developing with a separate form of recommended configuration data and business logic that is not captured in the above example, but is briefly described below. For example, enter a scenic spot and give the city where the scenic spot is located.

function getCityForScenic(scenic) {
    let _city=' '
    if(scenic===Canton Tower){
        _city='guangzhou'
    }
    else if(scenic==="West lake"){
        _city='hangzhou'
    }
    return _city;
}
Copy the code

Enter Canton tower and return to Guangzhou. Enter west Lake and return to Hangzhou. But a city has more than one scenic spot, so some people are used to writing this way.

if(scenic===Canton Tower||scenic==='Flower City Square'||scenic==='Baiyun Mountain'){
    _city='guangzhou'
}
Copy the code

If you have a lot of attractions, a lot of data, it’s hard to look at, some people like to write that

let scenicOfHangZhou=["West lake".'xianghu lake'.'Sand Boat Life Square'.'Beijing-Hangzhou Grand Canal'.'Imperial Street of southern Song Dynasty']
if(~scenicOfHangZhou.indexOf(scenic)){
    _city='hangzhou'
}
Copy the code

This is fine, but the code may be written differently, like the following.

function getCityForScenic(scenic) {
    let _city=' ';
    let scenicOfHangZhou=["West lake".'xianghu lake'.'Sand Boat Life Square'.'Beijing-Hangzhou Grand Canal'.'Imperial Street of southern Song Dynasty'];
    if(scenic===Canton Tower||scenic==='Flower City Square'||scenic==='Baiyun Mountain'){
        _city='guangzhou'
    }
    else if(~scenicOfHangZhou.indexOf(scenic)){
        _city='hangzhou'
    }
    return _city;
}
Copy the code

This can happen even with switch

function getCityForScenic(scenic) {
    let _city=' ';
    let scenicOfHangZhou=["West lake".'xianghu lake'.'Sand Boat Life Square'.'Beijing-Hangzhou Grand Canal'.'Imperial Street of southern Song Dynasty'];
	switch(true) {case (scenic===Canton Tower||scenic==='Flower City Square'||scenic==='Baiyun Mountain'):_city='guangzhou';break;
        case(!!!!! ~scenicOfHangZhou.indexOf(scenic)):return 'hangzhou';   
	}
	return 	_city;
}
Copy the code

The above code is unlikely to appear, but it will. Such code can be confusing in the future. This problem can be avoided if the separation of configuration data and business logic is used.

function getCityForScenic(scenic) {
    let cityConfig={
        Canton Tower:'guangzhou'.'Flower City Square':'guangzhou'.'Baiyun Mountain':'guangzhou'."West lake":'hangzhou'.'xianghu lake':'hangzhou'.'Beijing-Hangzhou Grand Canal':'hangzhou'.'Sand Boat Life Square':'hangzhou'.'Imperial Street of southern Song Dynasty':'hangzhou',}return cityConfig[scenic];
}
Copy the code

Some people are not used to the object’s key name being Chinese. You can be flexible

function getCityForScenic(scenic) {
    let cityConfig=[
        {
            scenic:Canton Tower,
            city:'guangzhou'
        },
        {
            scenic:'Flower City Square',
            city:'guangzhou'
        },
        {
            scenic:'Baiyun Mountain',
            city:'guangzhou'
        },
        {
            scenic:"West lake",
            city:'hangzhou'
        },
        {
            scenic:'xianghu lake',
            city:'hangzhou'
        },
        {
            scenic:'Beijing-Hangzhou Grand Canal',
            city:'hangzhou'
        },
        {
            scenic:'Sand Boat Life Square',
            city:'hangzhou'}]for(leti=0; i<cityConfig.length; i++){if(cityConfig[i].scenic===scenic){
            return cityConfig[i].city
        }
    }
}
Copy the code

In this way, if you want to add any scenic spots and corresponding cities in the future, you can only modify the above cityConfig, and the business logic does not need to be changed, nor can it be changed. The code style has been unified above.

Here is a summary of the benefits of separating configuration data from business logic

  1. Modifying configuration data is less costly and risky than modifying business logic
  2. Configuration data sources and modifications can be flexible
  3. The separation of configuration and business logic makes it easier to find code that needs to be changed
  4. Configuration data and business logic can unify the code style

However, this modification is not recommended for all if-else applications, and the look-up modification is not recommended for some requirements. For example, if-else is not very much, if judgment logic is not uniform use, or it is recommended to use if-else method to achieve. But the fairy numbers, to clear.

For example, the need to pass in a timestamp to show the time display of comments,

Comments posted less than 1 hour ago: X minutes ago

Post 1 hour to 24 hour comments: x hours ago

Comments posted 24 hours to 30 days ago: x days ago

Post comments more than 30 days old: month/day

Comments posted last year and more than 30 days old: year/month/day

It’s not hard to implement, a few if-else’s

functionFormatDate (timeStr){// Get the current timestamplet_now=+new Date(); // Find the difference with the current timelet se=_now-timeStr;
    let _text=' '; / / last yearif(new Date(timeStr).getFullYear()! ==new Date().getFullYear()&&se>2592000000){ _text=new Date(timeStr).getFullYear()+'years'+(new Date(timeStr).getMonth()+1)+'month'+new Date(timeStr).getDate()+'day'; } // More than 30 dayselse if(se>2592000000){
      _text=(new Date(timeStr).getMonth()+1)+'month'+new Date(timeStr).getDate()+'day'; } // More than one dayelse if(se>86400000){
      _text=Math.floor(se/86400000)+'days ago'; } // More than one hourelse if(se>3600000){
      _text=Math.floor(se/3600000)+'Hours ago'; } // Within an hourelse{// If less than 1 minute, 1 minute ago is displayedif(se<60000){se=60000}
      _text=Math.floor(se/60000)+'Minutes ago';
    }
    return _text;
}

Copy the code

The result is fine, but there is a problem that the requirement has fairy numbers: 259200000, 86400000, 3600000, 60000. For later maintenance, you may not know what this number is at first.

So the following elimination of fairy numbers, often quantified

functionFormatDate (timeStr){// Get the current timestamplet_now=+new Date(); // Find the difference with the current timelet se=_now-timeStr;
    const DATE_LEVEL={
      month:2592000000,
      day:86400000,
      hour:3600000,
      minter:60000,
    }
    let _text=' '; / / last yearif(new Date(timeStr).getFullYear()! ==new Date().getFullYear()&&se>DATE_LEVEL.month){ _text=new Date(timeStr).getFullYear()+'years'+(new Date(timeStr).getMonth()+1)+'month'+new Date(timeStr).getDate()+'day'; } // More than one monthelse if(se>DATE_LEVEL.month){
      _text=(new Date(timeStr).getMonth()+1)+'month'+new Date(timeStr).getDate()+'day'; } // More than one dayelse if(se>DATE_LEVEL.day){
      _text=Math.floor(se/DATE_LEVEL.day)+'days ago'; } // More than one hourelse if(se>DATE_LEVEL.hour){
      _text=Math.floor(se/DATE_LEVEL.hour)+'Hours ago'; } // Within an hourelse{// If less than 1 minute, 1 minute ago is displayedif(se<DATE_LEVEL.minter){se=DATE_LEVEL.minter}
      _text=Math.floor(se/DATE_LEVEL.minter)+'Minutes ago';
    }
    return _text;
}
Copy the code

The result is also correct, more code, but no fairy numbers. Readability is not bad either.

By the way, if the above requirements were forced to look up, the code would look like this. This makes code changes more extensible and less costly, but less readable. Trade-offs, actual situations, actual analysis.

functionFormatDate (timeStr){// Get the current timestamplet_now=+new Date(); // Find the difference with the current timelet se=_now-timeStr;
    let _text=' '; // Find the last second timestamp of the previous yearlet lastYearTime=new Date(new Date().getFullYear()+'- 01-01 00:00:00') - 1; // Add the time difference (the difference between the current timestamp and the last second of the previous year's timestamp). If the time difference (se) exceeds this value, it represents the time of the previous year. //DATE_LEVEL.unshift(_now-lastYearTime); const DATE_LEVEL={ month:2592000000, day:86400000, hour:3600000, minter:60000, }let handleFn=[
        {
			time:DATE_LEVEL.month,
            fn:function(timeStr){
                return (new Date(timeStr).getMonth()+1)+'month'+new Date(timeStr).getDate()+'day';
            }
		},
        {
			time:DATE_LEVEL.day,
            fn:function(timeStr){
                return Math.floor(se/DATE_LEVEL.day)+'days ago';
            }
		},
		{
			time:DATE_LEVEL.hour,
            fn:function(timeStr){
                return Math.floor(se/DATE_LEVEL.hour)+'Hours ago';
            }
		},
        {
			time:DATE_LEVEL.minter,
            fn:function(timeStr){
                return Math.ceil(se/DATE_LEVEL.minter)+'Minutes ago'; }}]; // Find the last second timestamp of the previous yearlet lastYearTime=new Date(new Date().getFullYear()+'- 01-01 00:00:00') - 1; // Add the time difference (the difference between the current timestamp and the last second of the previous year's timestamp) and the operation function. If the time difference (se) exceeds this value, it represents the time of the previous year. handleFn.unshift({ time:_now-lastYearTime, fn:function(timeStr){
		    if(se>DATE_LEVEL.month){
		        return new Date(timeStr).getFullYear()+'years'+(new Date(timeStr).getMonth()+1)+'month'+new Date(timeStr).getDate()+'day'; }}});let result=' ';
    for(leti=0; i<handleFn.length; i++){if(se>=handleFn[i].time){
            result=handleFn[i].fn(timeStr);
            if(result){
                returnresult; If the publication time is less than 1 minute, 1 minute is returnedreturn result='1 minute ago '
}
Copy the code

3. Configure objects to replace the Switch

For example, there is a demand: incoming cash, check, draft, ZFB, wX_pay, corresponding output: cash, check, money order, Alipay, wechat pay.

The requirements are simple, just a switch

function getPayChanne(tag){
    switch(tag){
        case 'cash':return 'cash';
        case 'check':return 'check';
        case 'draft':return 'bill';
        case 'zfb':return Alipay;
        case 'wx_pay':return 'wechat Pay'; }}Copy the code

But this is the same as above, in case next time you need to add a “bank_trans” to export the bank transfer, the code will have to be changed again. Similar problem, same solution, separation of configuration data and business logic. Here’s the code.

function getPayChanne(tag){
    let payChanneForChinese = {
        'cash': 'cash'.'check': 'check'.'draft': 'bill'.'zfb': Alipay.'wx_pay': 'wechat Pay'};return payChanneForChinese[tag];
}
Copy the code

Similarly, if you want to encapsulate a generic one, you can

let payChanneForChinese = {
    'cash': 'cash'.'check': 'check'.'draft': 'bill'.'zfb': Alipay.'wx_pay': 'wechat Pay'};function getPayChanne(tag,chineseConfig){
    return chineseConfig[tag];
}
getPayChanne('cash',payChanneForChinese);
Copy the code

Here’s the benefit of using objects instead of switches

  1. Using objects does not require the switch to traverse case by case.
  2. With objects, writing business logic can be more flexible
  3. Using objects separates configuration data from business logic. See the previous section for benefits.

4. Summary

There are so many recent alternatives to if-else and switch in certain situations. If-else, switch itself is right, mainly thinking about how to optimize the code, make the code more readable, extensible. If you have any better solutions or better implementations of other solutions. Leave a comment in the comments section.

— — — — — — — — — — — — — — — — — — — — — — — — — gorgeous line — — — — — — — — — — — — — — — — — — — —

Want to know more, pay attention to my wechat public number: Waiting book pavilion