• 技术文章 >web前端 >js教程

    消除if else, 让你的代码看起来更优雅

    coldplay.xixicoldplay.xixi2020-10-12 18:05:28转载156

    javascript栏目介绍如何消除if else, 让你的代码看起来更优雅,一起来看看吧。

    前言

    应该有不少同学有遇到过充斥着if else的代码,面对这样的一团乱麻,简单粗暴地继续增量修改常常只会让复杂度越来越高,可读性越来越差。那么是时候重构了,花几分钟看看这篇文章, 说不定对你有一丢丢帮助。

    场景一: 根据status显示对应名称

    优化方案1:object对象

    const statusStr = {
      '1': '待付款',
      '2': '待发货',
      '3': '已发货',
      '4': '交易完成',
      '5': '交易关闭',
      'default': '',
    }
    const getStatus = (status) =>{
      return statusStr[status] || statusStr['default']
    }

    将判断条件作为对象的属性名,将处理逻辑作为对象的属性值,在按钮点击的时候,通过对象属性查找的方式来进行逻辑判断.

    优化方案2: Map对象

    const statusStr = new map([
      '1': ['待付款'],
      '2': ['待发货'],
      '3': ['已发货'],
      '4': ['交易完成'],
      '5': ['交易关闭'],
      'default': [''],
    ])
    const getStatus = (status) =>{
      let actions = statusStr.get(status) || statusStr.get('default')
      return  actions[0];
    }

    这样写用到了es6里的Map对象,那么Map对象和Object对象有什么区别呢?

    一个对象通常都有自己的原型,所以一个对象总有一个"prototype"键。 一个对象的键只能是字符串或者Symbols,但一个Map的键可以是任意值。 你可以通过size属性很容易地得到一个Map的键值对个数,而对象的键值对个数只能手动确认。

    场景二:多个condition对应名称

    现在把问题升级一下, 以前按钮点击时候只需要判断status,现在还需要判断用户的身份:
    「举个栗子:」

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

    上面的例子我们可以看到,当你的逻辑升级为二元判断时,你的判断量会加倍,你的代码量也会加倍,这时怎么写更清爽呢?

    优化方案1: 将condition用字符拼接形式存在Map对象里

    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*/}],
    ])
    const onButtonClick = (identity,status)=>{
      let action = actions.get(`${identity}_${status}`) || actions.get('default')
      action.call(this)
    }

    上述代码核心逻辑是:把两个条件拼接成字符串,并通过以条件拼接字符串作为键,以处理函数作为值的Map对象进行查找并执行,这种写法在多元条件判断时候尤其好用。

    优化方案2: 将condition用字符拼接形式存在Object对象里

    const actions = {
      'guest_1':()=>{/*do sth*/},
      'guest_2':()=>{/*do sth*/},
      //....
    }
    const onButtonClick = (identity,status)=>{
      let action = actions[`${identity}_${status}`] || actions['default']
      action.call(this)
    }

    优化方案3: 将condition用Object对象形式存在Map对象里

    可能用查询条件拼成字符串有点别扭,那还有一种方案,就是用Map对象,以Object对象作为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))
    }

    场景三:根据status做出相应操作

    「举个栗子:」

    function init () {
        if (isAnswer === 1) {
            if (isOldUser === 1) {
                // ...
            } else if (isOldUser === 2) {
                // ...
            }
        } else if (isAnswer === 2) {
            if (isOldUser === 1) {
                // ...
            } else if (isOldUser === 2) {
                // ...
            }
        } else if (isAnswer === 3) {
            if (isOldUser === 1) {
                // ...
            } else if (isOldUser === 2) {
                // ...
            }
        }
    }

    优化方案1: 查找表,职责链查找表

    const rules = [
        {
            match (an, old) {if (an === 1) {return true}},
            action (an, old) {
            if (old === 1) {// ...} 
            else if (old === 2) {// ...}
            }
        },
        {
            match (an, old) { if (an === 2) {return true } },
            action (an, old) {
                if (old === 1) {// ...} 
                else if (old === 2) {// ...}
            }
        },
        {
            match (an, old) {if (an === 3) {return true}},
            action (an, old) {
                if (old === 1) {// ...} 
                else if (old === 2) {// ...}
            }
        }
    ]
    function init (an, old) {
        for (let i = 0; i < rules.length; i++) {
            // 如果返回true
            if (rules[i].match(an, old)) {
                rules[i].action(an, old)
            }
        }
    }
    init(isAnswer, isOldUser)

    虽然可能看着是治标不治本,其实不然,init函数的复杂度大大的降低了。我们已经把控制流程的复杂逻辑,拆分到determineAction函数中

    优化方案2: 函数式编程

    import R from 'ramda'
    var fn = R.cond([
      [R.equals(0),   R.always('water freezes at 0°C')],
      [R.equals(100), R.always('water boils at 100°C')],
      [R.T,           temp => 'nothing special happens at ' + temp + '°C']
    ]);
    fn(0); //=> 'water freezes at 0°C'
    fn(50); //=> 'nothing special happens at 50°C'
    fn(100); //=> 'water boils at 100°C'

    场景四: 根据范围去进行不同处理

    「举个栗子:」比如大家可能会遇到类似下面的需求:比如某平台的信用分数评级,超过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;
    }

    优化方案1: 用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, 但也不是所有的if else都需要替代, 视情况而定。

    更多相关免费学习:javascript(视频)

    以上就是消除if else, 让你的代码看起来更优雅的详细内容,更多请关注php中文网其它相关文章!

    本文转载于:juejin,如有侵犯,请联系a@php.cn删除
    专题推荐:if else js
    上一篇:深入了解JS中的for...of循环 下一篇:JavaScript中必须掌握的10个基础问题
    第13期线上培训班

    相关文章推荐

    • 抱着枸杞奋战多夜,我总结了JavaScript与ES的25个重要知识点• 杜绝这五个 Javascript 错误啦• 原生JavaScript实现弹幕组件de方法• 重学JavaScript 对象

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网