首頁 > web前端 > js教程 > 主體

消除if else, 讓你的程式碼看起來更優雅

coldplay.xixi
發布: 2020-10-12 18:05:28
轉載
2564 人瀏覽過

javascript專欄介紹如何消除if else, 讓你的程式碼看起來更優雅,一起來看看吧。

消除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 &#39;ramda&#39;
var fn = R.cond([
  [R.equals(0),   R.always(&#39;water freezes at 0°C&#39;)],
  [R.equals(100), R.always(&#39;water boils at 100°C&#39;)],
  [R.T,           temp => &#39;nothing special happens at &#39; + temp + &#39;°C&#39;]
]);
fn(0); //=> &#39;water freezes at 0°C&#39;
fn(50); //=> &#39;nothing special happens at 50°C&#39;
fn(100); //=> &#39;water boils at 100°C&#39;
登入後複製

場景四:依照範圍去進行不同處理

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

function showGrace(grace) {
    let _level=&#39;&#39;;
    if(grace>=700){
        _level=&#39;信用极好&#39;
    }
    else if(grace>=650){
        _level=&#39;信用优秀&#39;
    }
    else if(grace>=600){
        _level=&#39;信用良好&#39;
    }
    else if(grace>=550){
        _level=&#39;信用中等&#39;
    }
    else{
        _level=&#39;信用较差&#39;
    }
    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=[&#39;信用极好&#39;,&#39;信用优秀&#39;,&#39;信用良好&#39;,&#39;信用中等&#39;,&#39;信用较差&#39;];
登入後複製

小結

#很多情況下我們都可以使用更靈活的方式去替代if else以及switch, 但也不是所有的if else都需要替代, 視情況而定。

更多相關免費學習:javascript#(影片)

以上是消除if else, 讓你的程式碼看起來更優雅的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
js
來源:juejin.im
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板