[浅析]特定场景下庖代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;
}

《[浅析]特定场景下庖代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;i++){
        if(grace>=graceForLevel[i]){
            return levelText[i];
        }
    }
    //假如不存在,那末就是分数很低,返回末了一个
    return levelText[levelText.length-1];
}

如许的修正,长处就是假如有需求修正,只须要修正graceForLevel,levelText。营业逻辑不须要改。

为何这里引荐配数据置和营业逻辑星散

1.修正设置数据比营业逻辑修正本钱更小,风险更低

2.设置数据泉源和修正都能够很天真

3.荐设置和营业逻辑星散,能够更快的找到须要修正的代码

假如还想天真一些,能够封装一个轻微通用一点的look-up函数。

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

《[浅析]特定场景下庖代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='杭州'
}

《[浅析]特定场景下庖代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;i++){
        if(cityConfig[i].scenic===scenic){
            return cityConfig[i].city
        }
    }
}

如许一来,假如今后要加什么景点,对应什么都市,只能修正上面的cityConfig,营业逻辑不须要改,也不能改。代码作风上面就做到了一致。

这里简朴总结下,运用设置数据和营业逻辑星散的情势,优点

  1. 修正设置数据比营业逻辑修正本钱更小,风险更低
  2. 设置数据泉源和修正都能够很天真
  3. 设置和营业逻辑星散,能够更快的找到须要修正的代码
  4. 设置数据和营业逻辑能够让代码作风一致

然则并非一切的if-else都发起如许革新,有些需求不发起运用look-up革新。比方if-else不是许多,if推断的逻辑不一致的运用,照样发起运用if-else体式格局完成。然则仙人数字,要祛除。

比方下面这个根绝传入时候戳,显现批评时候显现的需求,

宣布1小时之内的批评:x分钟前

宣布1小时~24小时的批评:x小时前

宣布24小时~30天的批评:x天前

宣布30天以上的批评:月/日

客岁宣布而且凌驾30天的批评:年/月/日

完成不难,几个if-else就好了

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<60000){se=60000}
      _text=Math.floor(se/60000)+'分钟前';
    }
    return _text;
}

《[浅析]特定场景下庖代if-else和switch的计划》

运转效果没题目,然则也存在一个题目,就是这个需求有仙人数字:2592000000,86400000,3600000,60000。关于背面保护而言,一开始能够并不知道这个数字是什么东西。

所以下面就祛除仙人数字,常量化

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){se=DATE_LEVEL.minter}
      _text=Math.floor(se/DATE_LEVEL.minter)+'分钟前';
    }
    return _text;
}

运转效果也是准确的,代码多了,然则仙人数字没了。可读性也不差。

这里也趁便提一下,假如硬要把上面的需求改成look-up的体式格局,代码就是下面如许。如许代码的修正的扩展性会强一些,本钱会小一些,然则可读性不如上面。弃取关联,现实状况,现实剖析。

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;i++){
        if(se>=handleFn[i].time){
            result=handleFn[i].fn(timeStr);
            if(result){
                return result;
            }
        }
    }
    //假如宣布时候小于1分钟,之际返回1分钟
    return result='1分钟前'
}

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 '微信付出';
    }
}

《[浅析]特定场景下庖代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. 运用对象能够使得设置数据和营业逻辑星散。优点参考上一部分内容。

4.小结

最近在特定场合下,替代if-else和switch的解决计划就是这么多了。if-else,switch自身没错,主如果想着怎样优化代码,让代码越发具有可读性,扩展性。假如人人另有什么优化的计划或许对方面的计划有更好的完成计划。迎接在批评区留言。

————————-华美的分割线——————–

想相识更多,关注关注我的微信民众号:等待书阁

《[浅析]特定场景下庖代if-else和switch的计划》

    原文作者:守候
    原文地址: https://segmentfault.com/a/1190000015643488
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞