欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS復(fù)雜判斷的更優(yōu)雅寫法代碼詳解

 更新時間:2018年11月07日 08:54:27   作者:Think.  
我們編寫js代碼時經(jīng)常遇到復(fù)雜邏輯判的情況,通常大家可以用if/else或者switch來實(shí)現(xiàn)多個條件判斷,但這樣會有個問題,隨著邏輯復(fù)雜度的增加,代碼中的if/else/switch會變得越來越臃腫,越來越看不懂,那么如何更優(yōu)雅的寫判斷邏輯,本文帶你試一下

我們編寫js代碼時經(jīng)常遇到復(fù)雜邏輯判的情況,通常大家可以用if/else或者switch來實(shí)現(xiàn)多個條件判斷,但這樣會有個問題,隨著邏輯復(fù)雜度的增加,代碼中的if/else/switch會變得越來越臃腫,越來越看不懂,那么如何更優(yōu)雅的寫判斷邏輯,本文帶你試一下。

舉個例子

先看一段代碼

/**
 * 按鈕點(diǎn)擊事件
 * @param {number} status 活動狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消
 */
const onButtonClick1 = (status)=>{
 if(status == 1){
  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')
 }
}

通過代碼可以看到這個按鈕的點(diǎn)擊邏輯:根據(jù)不同活動狀態(tài)做兩件事情,發(fā)送日志埋點(diǎn)和跳轉(zhuǎn)到對應(yīng)頁面,大家可以很輕易的提出這段代碼的改寫方案,switch出場:

/**
 * 按鈕點(diǎn)擊事件
 * @param {number} status 活動狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消
 */
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清晰多了,細(xì)心的同學(xué)也發(fā)現(xiàn)了小技巧,case 2和case 3邏輯一樣的時候,可以省去執(zhí)行語句和break,則case 2的情況自動執(zhí)行case 3的邏輯。

這時有同學(xué)會說,還有更簡單的寫法:

const actions = {
 '1': ['processing','IndexPage'],
 '2': ['fail','FailPage'],
 '3': ['fail','FailPage'],
 '4': ['success','SuccessPage'],
 '5': ['cancel','CancelPage'],
 'default': ['other','Index'],
}
/**
 * 按鈕點(diǎn)擊事件
 * @param {number} status 活動狀態(tài):1開團(tuán)進(jìn)行中 2開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消
 */
const onButtonClick = (status)=>{
 let action = actions[status] || actions['default'],
   logName = action[0],
   pageName = action[1]
 sendLog(logName)
 jumpTo(pageName)
}

上面代碼確實(shí)看起來更清爽了,這種方法的聰明之處在于:將判斷條件作為對象的屬性名,將處理邏輯作為對象的屬性值,在按鈕點(diǎn)擊的時候,通過對象屬性查找的方式來進(jìn)行邏輯判斷,這種寫法特別適合一元條件判斷的情況。

是不是還有其他寫法呢?有的:

const actions = new Map([
 [1, ['processing','IndexPage']],
 [2, ['fail','FailPage']],
 [3, ['fail','FailPage']],
 [4, ['success','SuccessPage']],
 [5, ['cancel','CancelPage']],
 ['default', ['other','Index']]
])
/**
 * 按鈕點(diǎn)擊事件
 * @param {number} status 活動狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 商品售罄 4 開團(tuán)成功 5 系統(tǒng)取消
 */
const onButtonClick = (status)=>{
 let action = actions.get(status) || actions.get('default')
 sendLog(action[0])
 jumpTo(action[1])
}

這樣寫用到了es6里的Map對象,是不是更爽了?Map對象和Object對象有什么區(qū)別呢?

一個對象通常都有自己的原型,所以一個對象總有一個"prototype"鍵。
一個對象的鍵只能是字符串或者Symbols,但一個Map的鍵可以是任意值。

你可以通過size屬性很容易地得到一個Map的鍵值對個數(shù),而對象的鍵值對個數(shù)只能手動確認(rèn)。

我們需要把問題升級一下,以前按鈕點(diǎn)擊時候只需要判斷status,現(xiàn)在還需要判斷用戶的身份:

/**
 * 按鈕點(diǎn)擊事件
 * @param {number} status 活動狀態(tài):1開團(tuán)進(jìn)行中 2開團(tuán)失敗 3 開團(tuán)成功 4 商品售罄 5 有庫存未開團(tuán)
 * @param {string} identity 身份標(biāo)識:guest客態(tài) master主態(tài)
 */
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
  }
 }
}

原諒我不寫每個判斷里的具體邏輯了,因?yàn)榇a太冗長了。

原諒我又用了if/else,因?yàn)槲铱吹胶芏嗳艘廊辉谟胕f/else寫這種大段的邏輯判斷。

從上面的例子我們可以看到,當(dāng)你的邏輯升級為二元判斷時,你的判斷量會加倍,你的代碼量也會加倍,這時怎么寫更清爽呢?

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

/**
 * 按鈕點(diǎn)擊事件
 * @param {string} identity 身份標(biāo)識:guest客態(tài) master主態(tài)
 * @param {number} status 活動狀態(tài):1 開團(tuán)進(jìn)行中 2 開團(tuán)失敗 3 開團(tuán)成功 4 商品售罄 5 有庫存未開團(tuán)
 */
const onButtonClick = (identity,status)=>{
 let action = actions.get(`${identity}_${status}`) || actions.get('default')
 action.call(this)
}

上述代碼核心邏輯是:把兩個條件拼接成字符串,并通過以條件拼接字符串作為鍵,以處理函數(shù)作為值的Map對象進(jìn)行查找并執(zhí)行,這種寫法在多元條件判斷時候尤其好用。

當(dāng)然上述代碼如果用Object對象來實(shí)現(xiàn)也是類似的:

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

如果有些同學(xué)覺得把查詢條件拼成字符串有點(diǎn)別扭,那還有一種方案,就是用Map對象,以O(shè)bject對象作為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))
}

是不是又高級了一點(diǎn)點(diǎn)?

這里也看出來Map與Object的區(qū)別,Map可以用任何類型的數(shù)據(jù)作為key。

我們現(xiàn)在再將難度升級一點(diǎn)點(diǎn),假如guest情況下,status1-4的處理邏輯都一樣怎么辦,最差的情況是這樣:

const actions = new Map([
 [{identity:'guest',status:1},()=>{/* functionA */}],
 [{identity:'guest',status:2},()=>{/* functionA */}],
 [{identity:'guest',status:3},()=>{/* functionA */}],
 [{identity:'guest',status:4},()=>{/* functionA */}],
 [{identity:'guest',status:5},()=>{/* functionB */}],
 //...
])

好一點(diǎn)的寫法是將處理邏輯函數(shù)進(jìn)行緩存:

const actions = ()=>{
 const functionA = ()=>{/*do sth*/}
 const functionB = ()=>{/*do sth*/}
 return new Map([
  [{identity:'guest',status:1},functionA],
  [{identity:'guest',status:2},functionA],
  [{identity:'guest',status:3},functionA],
  [{identity:'guest',status:4},functionA],
  [{identity:'guest',status:5},functionB],
  //...
 ])
}

const onButtonClick = (identity,status)=>{
 let action = [...actions()].filter(([key,value])=>(key.identity == identity && key.status == status))
 action.forEach(([key,value])=>value.call(this))
}

這樣寫已經(jīng)能滿足日常需求了,但認(rèn)真一點(diǎn)講,上面重寫了4次functionA還是有點(diǎn)不爽,假如判斷條件變得特別復(fù)雜,比如identity有3種狀態(tài),status有10種狀態(tài),那你需要定義30條處理邏輯,而往往這些邏輯里面很多都是相同的,這似乎也是筆者不想接受的,那可以這樣實(shí)現(xiàn):

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的優(yōu)勢更加凸顯,可以用正則類型作為key了,這樣就有了無限可能,假如需求變成,凡是guest情況都要發(fā)送一個日志埋點(diǎn),不同status情況也需要單獨(dú)的邏輯處理,那我們可以這樣寫:

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

也就是說利用數(shù)組循環(huán)的特性,符合正則條件的邏輯都會被執(zhí)行,那就可以同時執(zhí)行公共邏輯和單獨(dú)邏輯,因?yàn)檎齽t的存在,你可以打開想象力解鎖更多的玩法,本文就不贅述了。

總結(jié)

以上所述是小編給大家介紹的JS復(fù)雜判斷的更優(yōu)雅寫法代碼詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • 微信小程序 下拉刷新及上拉加載原理解析

    微信小程序 下拉刷新及上拉加載原理解析

    這篇文章主要介紹了微信小程序 下拉刷新及上拉加載實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • js原生實(shí)現(xiàn)FastClick事件的實(shí)例

    js原生實(shí)現(xiàn)FastClick事件的實(shí)例

    下面小編就為大家?guī)硪黄猨s原生實(shí)現(xiàn)FastClick事件的實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • js函數(shù)定時器實(shí)現(xiàn)定時讀取系統(tǒng)實(shí)時連接數(shù)

    js函數(shù)定時器實(shí)現(xiàn)定時讀取系統(tǒng)實(shí)時連接數(shù)

    這篇文章主要介紹了使用js函數(shù)定時器實(shí)現(xiàn)定時讀取系統(tǒng)實(shí)時連接數(shù),需要的朋友可以參考下
    2014-04-04
  • JS循環(huán)遍歷JSON數(shù)據(jù)的方法

    JS循環(huán)遍歷JSON數(shù)據(jù)的方法

    這篇文章主要介紹了JS 循環(huán)遍歷JSON數(shù)據(jù)的方法,需要的朋友可以參考下
    2014-07-07
  • 原生JS實(shí)現(xiàn)目錄滾動特效

    原生JS實(shí)現(xiàn)目錄滾動特效

    這篇文章主要為大家詳細(xì)介紹了原生JS實(shí)現(xiàn)目錄滾動特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • 如何在js中計算兩個時間段重疊的時長問題詳解

    如何在js中計算兩個時間段重疊的時長問題詳解

    這篇文章主要給大家介紹了關(guān)于如何在js中計算兩個時間段重疊的時長問題的相關(guān)資料,判斷兩個時間段是否重疊可以通過比較兩個時間段的開始時間和結(jié)束時間來實(shí)現(xiàn),文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2024-04-04
  • JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理

    JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理

    JavaScript中的事件循環(huán)機(jī)制是一種異步處理機(jī)制,通過維護(hù)事件隊(duì)列和消息隊(duì)列,實(shí)現(xiàn)任務(wù)的分發(fā)和執(zhí)行。事件循環(huán)機(jī)制由主線程和任務(wù)隊(duì)列構(gòu)成,主線程運(yùn)行完當(dāng)前任務(wù)后會檢查任務(wù)隊(duì)列中是否有待執(zhí)行的任務(wù),如有則執(zhí)行,否則等待
    2023-04-04
  • 談?wù)凧avaScript數(shù)組常用方法總結(jié)

    談?wù)凧avaScript數(shù)組常用方法總結(jié)

    本篇文章主要介紹了談?wù)凧avaScript數(shù)組常用方法總結(jié),在JavaScript中,我們需要時常對數(shù)組進(jìn)行操作。一起跟隨小編過來看看吧
    2017-01-01
  • Javascript如何實(shí)現(xiàn)對象扁平化實(shí)例詳解

    Javascript如何實(shí)現(xiàn)對象扁平化實(shí)例詳解

    這篇文章主要給大家介紹了關(guān)于Javascript如何實(shí)現(xiàn)對象扁平化的扁平化處理簡而言之就是對對象中的對象提取出來,放在一個對象里面,形象的說就是把兒子的后代當(dāng)成自己的兒子,下面相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • js加減乘除丟失精度問題解決方法

    js加減乘除丟失精度問題解決方法

    在javascript中,帶小數(shù)的數(shù)據(jù)運(yùn)算時總會出現(xiàn)好多位小數(shù).這是因?yàn)樵趈avascript中浮點(diǎn)數(shù)的計算是以2進(jìn)制計算的
    2014-05-05

最新評論