js中如何優雅的寫if判斷

咱們編寫js代碼時常常遇到複雜邏輯判斷的狀況,一般你們能夠用if/else或者switch來實現多個條件判斷,但這樣會有個問題,隨着邏輯複雜度的增長,代碼中的if/else/switch會變得愈來愈臃腫,愈來愈看不懂,那麼如何更優雅的寫判斷邏輯,本文帶你試一下。es6

舉個例子

先看一段代碼數組

/**緩存

 * 按鈕點擊事件ide

 * @param {number} status 活動狀態:1 開團進行中 2 開團失敗 3 商品售罄 4 開團成功 5 系統取消函數

 */this

const onButtonClick (status={spa

  if (status == 1{prototype

    sendLog('processing'jumpTo('IndexPage')日誌

  else if (status == 2{對象

    sendLog('fail'jumpTo('FailPage')

  else if (status == 3{

    sendLog('fail'jumpTo('FailPage')

  else if (status == 4{

    sendLog('success'jumpTo('SuccessPage')

  else if (status == 5{

    sendLog('cancel'jumpTo('CancelPage')

  else {

    sendLog('other'jumpTo('Index')

  }

}

經過代碼能夠看到這個按鈕的點擊邏輯:根據不一樣活動狀態作兩件事情,發送日誌埋點和跳轉到對應頁面,你們能夠很輕易的提出這段代碼的改寫方案,switch出場:

/**

 * 按鈕點擊事件

 * @param {number} status 活動狀態:1 開團進行中 2 開團失敗 3 商品售罄 4 開團成功 5 系統取消

 */

const onButtonClick (status={

  switch (status{

    case 1:

      sendLog('processing')

      jumpTo('IndexPage')

      break

    case 2:

    case 3:

      sendLog('fail')

      jumpTo('FailPage')

      break

    case 4:

      sendLog('success')

      jumpTo('SuccessPage')

      break

    case 5:

      sendLog('cancel')

      jumpTo('CancelPage')

      break

    default:

      sendLog('other')

      jumpTo('Index')

      break

  }

}

嗯,這樣看起來比if/else清晰多了,細心的同窗也發現了小技巧,case 2和case 3邏輯同樣的時候,能夠省去執行語句和break,則case 2的狀況自動執行case 3的邏輯。

這時有同窗會說,還有更簡單的寫法:

const actions {

  '1'['processing''IndexPage'],

  '2'['fail''FailPage'],

  '3'['fail''FailPage'],

  '4'['success''SuccessPage'],

  '5'['cancel''CancelPage'],

  'default'['other''Index'],

}

/**

 * 按鈕點擊事件

 * @param {number} status 活動狀態:1開團進行中 2開團失敗 3 商品售罄 4 開團成功 5 系統取消

 */

const onButtonClick (status={

  let action = actions[status|| actions['default'],

    logName = action[0],

    pageName = action[1]

  sendLog(logName)

  jumpTo(pageName)

}

上面代碼確實看起來更清爽了,這種方法的聰明之處在於:將判斷條件做爲對象的屬性名,將處理邏輯做爲對象的屬性值,在按鈕點擊的時候,經過對象屬性查找的方式來進行邏輯判斷,這種寫法特別適合一元條件判斷的狀況。

是否是還有其餘寫法呢?有的:

const actions new Map([

  [1['processing''IndexPage']],

  [2['fail''FailPage']],

  [3['fail''FailPage']],

  [4['success''SuccessPage']],

  [5['cancel''CancelPage']],

  ['default'['other''Index']]

])

/**

 * 按鈕點擊事件

 * @param {number} status 活動狀態:1 開團進行中 2 開團失敗 3 商品售罄 4 開團成功 5 系統取消

 */

const onButtonClick (status={

  let action = actions.get(status|| actions.get('default')

  sendLog(action[0])

  jumpTo(action[1])

}

這樣寫用到了es6裏的Map對象,是否是更爽了?Map對象和Object對象有什麼區別呢?

  1. 一個對象一般都有本身的原型,因此一個對象總有一個"prototype"鍵。

  2. 一個對象的鍵只能是字符串或者Symbols,但一個Map的鍵能夠是任意值。

  3. 你能夠經過size屬性很容易地獲得一個Map的鍵值對個數,而對象的鍵值對個數只能手動確認。

咱們須要把問題升級一下,之前按鈕點擊時候只須要判斷status,如今還須要判斷用戶的身份:

/**

 * 按鈕點擊事件

 * @param {number} status 活動狀態:1開團進行中 2開團失敗 3 開團成功 4 商品售罄 5 有庫存未開團

 * @param {string} identity 身份標識:guest客態 master主態

 */

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

    }

  }

}

原諒我不寫每一個判斷裏的具體邏輯了,由於代碼太冗長了。

原諒我又用了if/else,由於我看到不少人依然在用if/else寫這種大段的邏輯判斷。

從上面的例子咱們能夠看到,當你的邏輯升級爲二元判斷時,你的判斷量會加倍,你的代碼量也會加倍,這時怎麼寫更清爽呢?

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*/ }],

])

 

/**

 * 按鈕點擊事件

 * @param {string} identity 身份標識:guest客態 master主態

 * @param {number} status 活動狀態:1 開團進行中 2 開團失敗 3 開團成功 4 商品售罄 5 有庫存未開團

 */

const onButtonClick (identity, status={

  let action = actions.get(`${identity}_${status}`|| actions.get('default')

  action.call(this)

}

上述代碼核心邏輯是:把兩個條件拼接成字符串,並經過以條件拼接字符串做爲鍵,以處理函數做爲值的Map對象進行查找並執行,這種寫法在多元條件判斷時候尤爲好用。

固然上述代碼若是用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)

}

若是有些同窗以爲把查詢條件拼成字符串有點彆扭,那還有一種方案,就是用Map對象,以Object對象做爲key:

const actions new Map([

  [{

    identity'guest',

    status1

  }(=/*do sth*/ }],

  [{

    identity'guest',

    status2

  }(=/*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))

}

是否是又高級了一點點?

這裏也看出來Map與Object的區別,Map能夠用任何類型的數據做爲key。

咱們如今再將難度升級一點點,假如guest狀況下,status1-4的處理邏輯都同樣怎麼辦,最差的狀況是這樣:

const actions new Map([

  [{

    identity'guest',

    status1

  }(=/* functionA */ }],

  [{

    identity'guest',

    status2

  }(=/* functionA */ }],

  [{

    identity'guest',

    status3

  }(=/* functionA */ }],

  [{

    identity'guest',

    status4

  }(=/* functionA */ }],

  [{

    identity'guest',

    status5

  }(=/* functionB */ }],

  //...

])

好一點的寫法是將處理邏輯函數進行緩存:

const actions (={

  const functionA (=/*do sth*/ }

  const functionB (=/*do sth*/ }

  return new Map([

    [{

      identity'guest',

      status1

    }, functionA],

    [{

      identity'guest',

      status2

    }, functionA],

    [{

      identity'guest',

      status3

    }, functionA],

    [{

      identity'guest',

      status4

    }, functionA],

    [{

      identity'guest',

      status5

    }, functionB],

    //...

  ])

}

 

const onButtonClick (identity, status={

  let action [...actions()].filter(([key, value]=(key.identity == identity && key.status == status))

  action.forEach(([key, value]=> value.call(this))

}

這樣寫已經能知足平常需求了,但認真一點講,上面重寫了4次functionA仍是有點不爽,假如判斷條件變得特別複雜,好比identity有3種狀態,status有10種狀態,那你須要定義30條處理邏輯,而每每這些邏輯裏面不少都是相同的,這彷佛也是筆者不想接受的,那能夠這樣實現:

const actions (={

  const functionA (=/*do sth*/ }

  const functionB (=/*do sth*/ }

  return new Map([

    [/^guest_[1-4]$/, functionA],

    [/^guest_5$/, functionB],

    //...

  ])

}

 

const onButtonClick (identity, status={

  let action [...actions()].filter(([key, value]=(key.test(`${identity}_${status}`)))

  action.forEach(([key, value]=> value.call(this))

}

這裏Map的優點更加凸顯,能夠用正則類型做爲key了,這樣就有了無限可能,假如需求變成,凡是guest狀況都要發送一個日誌埋點,不一樣status狀況也須要單獨的邏輯處理,那咱們能夠這樣寫:

const actions (={

  const functionA (=/*do sth*/ }

  const functionB (=/*do sth*/ }

  const functionC (=/*send log*/ }

  return new Map([

    [/^guest_[1-4]$/, functionA],

    [/^guest_5$/, functionB],

    [/^guest_.*$/, functionC],

    //...

  ])

}

 

const onButtonClick (identity, status={

  let action [...actions()].filter(([key, value]=(key.test(`${identity}_${status}`)))

  action.forEach(([key, value]=> value.call(this))

}

也就是說利用數組循環的特性,符合正則條件的邏輯都會被執行,那就能夠同時執行公共邏輯和單獨邏輯,由於正則的存在,你能夠打開想象力解鎖更多的玩法,本文就不贅述了。

總結

本文已經教你了8種邏輯判斷寫法,包括:

  1. if/else

  2. switch

  3. 一元判斷時:存到Object裏

  4. 一元判斷時:存到Map裏

  5. 多元判斷時:將condition拼接成字符串存到Object裏

  6. 多元判斷時:將condition拼接成字符串存到Map裏

  7. 多元判斷時:將condition存爲Object存到Map裏

  8. 多元判斷時:將condition寫做正則存到Map裏

至此,本文也將告一段落,願你將來的人生裏,不僅是有if/else/switch。

相關文章
相關標籤/搜索