首頁 >web前端 >js教程 >js中如何取代if-else和switch

js中如何取代if-else和switch

不言
不言原創
2018-07-16 09:56:494296瀏覽

這篇文章主要介紹了關於js中如何取代if-else和switch,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

1.前言

相信很多人有這樣的經歷,在專案比較忙的時候,都是先考慮實現,用當時以為最好的方式先實現方案,在專案不忙的時候,再看下以前程式碼,想下有什麼更好的實作方案,或是最佳化方案。筆者也不例外,以下就和讀者們分享自己最近在特定場合下,取代if-else,switch的解決方案。如果大家有什麼想法,歡迎在留言區留言,大家多多交流。

2.look-up表代替if-else

例如大家可能會遇到類似下面的需求:例如某平台的信用分數評級,超過700-950,就是信用極佳,650-700信用優秀,600-650信用良好,550-600信用中等,350-550信用較差。

實作很簡單

function showGrace(grace) {
    let _level='';
    if(grace>=700){
        _level='信用极好'
    }
    else if(grace>=650){
        _level='信用优秀'
    }
    else if(grace>=600){
        _level='信用良好'
    }
    else if(grace>=550){
        _level='信用中等'
    }
    else{
        _level='信用较差'
    }
    return _level;
}

js中如何取代if-else和switch

運行也沒問題,但是問題也是有

1.萬一以後需求,改了比如650-750是信用優秀,750-950是信用極佳。這樣就整個方法要改。

2.方法存在各種神仙數字:700,650,600,550。日後的維護可能有問題。

3.if-else太多,看著有點強迫症

所以下面用look-up表,把配資料置和業務邏輯分離的方式實作下

function showGrace(grace) {
    let graceForLevel=[700,650,600,550];
    let levelText=['信用极好','信用优秀','信用良好','信用中等','信用较差'];
    for(let i=0;i<graceforlevel.length>=graceForLevel[i]){
            return levelText[i];
        }
    }
    //如果不存在,那么就是分数很低,返回最后一个
    return levelText[levelText.length-1];
}</graceforlevel.length>

這樣的修改,優點就是如果有需求修改,只需要修改graceForLevel,levelText。業務邏輯不需要改變。

為什麼這裡推薦配資料置和業務邏輯分離

1.修改設定資料比業務邏輯修改成本更小,風險更低

2.設定資料來源和修改都可以很靈活

3.薦配置和業務邏輯分離,可以更快的找到需要修改的程式碼

如果還想靈活一些,可以封裝一個稍微通用一點的look- up函數。

function showGrace(grace,level,levelForGrace) {
    for(let i=0;i<level.length>=level[i]){
            return levelForGrace[i];
        }
    }
    //如果不存在,那么就是分数很低,返回最后一个
    return levelForGrace[levelText.length-1];
}
let graceForLevel=[700,650,600,550];
let levelText=['信用极好','信用优秀','信用良好','信用中等','信用较差'];</level.length>

js中如何取代if-else和switch

使用推薦配置資料和業務邏輯分離形式開發,還有一個好處,在上面例子沒體現出來,下面簡單說下。例如輸入一個景點,給出景點所在的城市。

function getCityForScenic(scenic) {
    let _city=''
    if(scenic==='广州塔'){
        _city='广州'
    }
    else if(scenic==='西湖'){
        _city='杭州'
    }
    return _city;
}

輸入廣州塔,就回廣州。輸入西湖就返回杭州。但是一個城市不只一個景點,那麼有人習慣這樣寫。

if(scenic==='广州塔'||scenic==='花城广场'||scenic==='白云山'){
    _city='广州'
}

如果景點很多,資料很長,看著難受,有些人喜歡這樣寫

let scenicOfHangZhou=['西湖','湘湖','砂之船生活广场','京杭大运河','南宋御街']
if(~scenicOfHangZhou.indexOf(scenic)){
    _city='杭州'
}

js中如何取代if-else和switch

這樣執行沒錯,但是寫出來的程式碼可能像下面這樣,風格不統一

function getCityForScenic(scenic) {
    let _city='';
    let scenicOfHangZhou=['西湖','湘湖','砂之船生活广场','京杭大运河','南宋御街'];
    if(scenic==='广州塔'||scenic==='花城广场'||scenic==='白云山'){
        _city='广州'
    }
    else if(~scenicOfHangZhou.indexOf(scenic)){
        _city='杭州'
    }
    return _city;
}

即使用switch,也有可能出現這樣的情況

function getCityForScenic(scenic) {
    let _city='';
    let scenicOfHangZhou=['西湖','湘湖','砂之船生活广场','京杭大运河','南宋御街'];
    switch(true){
        case (scenic==='广州塔'||scenic==='花城广场'||scenic==='白云山'):_city='广州';break;
        case (!!~scenicOfHangZhou.indexOf(scenic)):return '杭州';   
    }
    return     _city;
}

雖然上面的程式碼出現的機率很小,但畢竟會出現。這樣的程式碼可能會造成日後維看得眼花撩亂。如果使用了配置資料和業務邏輯分離,那就可以避免這個問題。

function getCityForScenic(scenic) {
    let cityConfig={
        '广州塔':'广州',
        '花城广场':'广州',
        '白云山':'广州',
        '西湖':'杭州',
        '湘湖':'杭州',
        '京杭大运河':'杭州',
        '砂之船生活广场':'杭州',
        '南宋御街':'杭州',
    }
    
    return cityConfig[scenic];
}
有些人不習慣物件的 key 名是中文。也可以靈活處理
function getCityForScenic(scenic) {
    let cityConfig=[
        {
            scenic:'广州塔',
            city:'广州'
        },
        {
            scenic:'花城广场',
            city:'广州'
        },
        {
            scenic:'白云山',
            city:'广州'
        },
        {
            scenic:'西湖',
            city:'杭州'
        },
        {
            scenic:'湘湖',
            city:'杭州'
        },
        {
            scenic:'京杭大运河',
            city:'杭州'
        },
        {
            scenic:'砂之船生活广场',
            city:'杭州'
        }
    ]
    for(let i=0;i<cityconfig.length><p>這樣一來,如果以後要加什麼景點,對應什麼城市,只能修改上面的cityConfig,業務邏輯不需要改,也不能改。程式碼風格上面就做到了統一。 </p>
<p><strong>這裡簡單總結下,使用配置資料和業務邏輯分離的形式,好處</strong></p>
<ol class=" list-paddingleft-2">
<li><p>修改配置資料比業務邏輯修改成本更小,風險更低</p></li>
<li><p>配置資料來源和修改都可以很靈活</p></li>
<li><p>配置和業務邏輯分離,可以更快的找到需要修改的程式碼</p></li>
<li><p>配置資料和業務邏輯可以讓程式碼風格統一</p></li>
</ol>
<blockquote>但是並不是所有的if-else都建議這樣改造,有些需求不建議使用look-up改造。例如if-else不是很多,if判斷的邏輯不統一的使用,還是建議使用if-else方式實作。但是神仙數字,要清除。 </blockquote>
<p>例如下面這個根絕傳入時間戳,顯示評論時間顯示的需求,</p>
<p><strong>#發布1小時以內的評論:x分鐘前</strong></p>
<p> <strong>發布1小時~24小時的評論:x小時前</strong></p>
<p><strong>發布24小時~30天的評論:x天前</strong></p>
<p><strong>發佈30天以上的評論:月/日</strong></p>
<p><strong>去年發布並且超過30天的評論:年/月/日</strong></p>##實現不難,幾個if-else就行了<p></p>
<pre class="brush:php;toolbar:false">function formatDate(timeStr){
    //获取当前时间戳
    let _now=+new Date();
    //求与当前的时间差
    let se=_now-timeStr;
    let _text='';
    //去年
    if(new Date(timeStr).getFullYear()!==new Date().getFullYear()&&se>2592000000){
      _text=new Date(timeStr).getFullYear()+'年'+(new Date(timeStr).getMonth()+1)+'月'+new Date(timeStr).getDate()+'日';
    }
    //30天以上
    else if(se>2592000000){
      _text=(new Date(timeStr).getMonth()+1)+'月'+new Date(timeStr).getDate()+'日';
    }
    //一天以上
    else if(se>86400000){
      _text=Math.floor(se/86400000)+'天前';
    }
    //一个小时以上
    else if(se>3600000){
      _text=Math.floor(se/3600000)+'小时前';
    }
    //一个小时以内
    else{
      //如果小于1分钟,就显示1分钟前
      if(se<p style="text-align: center;"><img src="https://img.php.cn//upload/image/382/741/424/1531706091492473.jpg" title="1531706091492473.jpg" alt="js中如何取代if-else和switch">#</p><p>运行结果没问题,但是也存在一个问题,就是这个需求有神仙数字:2592000000,86400000,3600000,60000。对于后面维护而言,一开始可能并不知道这个数字是什么东西。</p><p>所以下面就消灭神仙数字,常量化</p><pre class="brush:php;toolbar:false">function formatDate(timeStr){
    //获取当前时间戳
    let _now=+new Date();
    //求与当前的时间差
    let se=_now-timeStr;
    const DATE_LEVEL={
      month:2592000000,
      day:86400000,
      hour:3600000,
      minter:60000,
    }
    let _text='';
    //去年
    if(new Date(timeStr).getFullYear()!==new Date().getFullYear()&&se>DATE_LEVEL.month){
      _text=new Date(timeStr).getFullYear()+'年'+(new Date(timeStr).getMonth()+1)+'月'+new Date(timeStr).getDate()+'日';
    }
    //一个月以上
    else if(se>DATE_LEVEL.month){
      _text=(new Date(timeStr).getMonth()+1)+'月'+new Date(timeStr).getDate()+'日';
    }
    //一天以上
    else if(se>DATE_LEVEL.day){
      _text=Math.floor(se/DATE_LEVEL.day)+'天前';
    }
    //一个小时以上
    else if(se>DATE_LEVEL.hour){
      _text=Math.floor(se/DATE_LEVEL.hour)+'小时前';
    }
    //一个小时以内
    else{
      //如果小于1分钟,就显示1分钟前
      if(se<date_level.minter><p>运行结果也是正确的,代码多了,但是神仙数字没了。可读性也不差。</p>
<blockquote>这里也顺便提一下,如果硬要把上面的需求改成look-up的方式,代码就是下面这样。这样代码的修改的扩展性会强一些,成本会小一些,但是可读性不如上面。取舍关系,实际情况,实际分析。</blockquote>
<pre class="brush:php;toolbar:false">function formatDate(timeStr){
    //获取当前时间戳
    let _now=+new Date();
    //求与当前的时间差
    let se=_now-timeStr;
    let _text='';
    //求上一年最后一秒的时间戳
    let lastYearTime=new Date(new Date().getFullYear()+'-01-01 00:00:00')-1;
    //把时间差添加进去(当前时间戳与上一年最后一秒的时间戳的差)添加进去,如果时间差(se)超过这个值,则代表了这个时间是上一年的时间。
    //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)+'月'+new Date(timeStr).getDate()+'日';
            }
        },
        {
            time:DATE_LEVEL.day,
            fn:function(timeStr){
                return Math.floor(se/DATE_LEVEL.day)+'天前';
            }
        },
        {
            time:DATE_LEVEL.hour,
            fn:function(timeStr){
                return Math.floor(se/DATE_LEVEL.hour)+'小时前';
            }
        },
        {
            time:DATE_LEVEL.minter,
            fn:function(timeStr){
                return Math.ceil(se/DATE_LEVEL.minter)+'分钟前';
            }
        } 
    ];
    //求上一年最后一秒的时间戳
    let lastYearTime=new Date(new Date().getFullYear()+'-01-01 00:00:00')-1;
    //把时间差(当前时间戳与上一年最后一秒的时间戳的差)和操作函数添加进去,如果时间差(se)超过这个值,则代表了这个时间是上一年的时间。
    handleFn.unshift({
        time:_now-lastYearTime,
        fn:function(timeStr){
            if(se>DATE_LEVEL.month){
                return new Date(timeStr).getFullYear()+'年'+(new Date(timeStr).getMonth()+1)+'月'+new Date(timeStr).getDate()+'日';
                
            }
        },
    });
    let result='';
    for(let i=0;i<handlefn.length>=handleFn[i].time){
            result=handleFn[i].fn(timeStr);
            if(result){
                return result;
            }
        }
    }
    //如果发布时间小于1分钟,之际返回1分钟
    return result='1分钟前'
}</handlefn.length>

3.配置对象代替switch

比如有一个需求:传入cash,check,draft,zfb,wx_pay,对应输出:现金,支票,汇票,支付宝,微信支付。

需求也很简单,就一个switch就搞定了

function getPayChanne(tag){
    switch(tag){
        case 'cash':return '现金';
        case 'check':return '支票';
        case 'draft':return '汇票';
        case 'zfb':return '支付宝';
        case 'wx_pay':return '微信支付';
    }
}

js中如何取代if-else和switch

但是这个的硬伤还是和上面一样,万一下次又要多加一个如:bank_trans对应输出银行转账呢,代码又要改。类似的问题,同样的解决方案,配置数据和业务逻辑分离。代码如下。

function getPayChanne(tag){
    let payChanneForChinese = {
        'cash': '现金',
        'check': '支票',
        'draft': '汇票',
        'zfb': '支付宝',
        'wx_pay': '微信支付',
    };
    return payChanneForChinese[tag];
}

同理,如果想封装一个通用的,也可以的

let payChanneForChinese = {
    'cash': '现金',
    'check': '支票',
    'draft': '汇票',
    'zfb': '支付宝',
    'wx_pay': '微信支付',
};
function getPayChanne(tag,chineseConfig){
    return chineseConfig[tag];
}
getPayChanne('cash',payChanneForChinese);

这里使用对象代替 switch 好处就在于

  1. 使用对象不需要 switch 逐个 case 遍历判断。

  2. 使用对象,编写业务逻辑可能更灵活

  3. 使用对象可以使得配置数据和业务逻辑分离。好处参考上一部分内容。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

以上是js中如何取代if-else和switch的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn