對于js的復雜判斷if/else和switch...case钞翔,這兩個我就不多說了适秩,下面我直接介紹比較優(yōu)雅的寫法:
第一種:
//報告期轉(zhuǎn)換(202001YY -> 2020年)
function translate(bgq) {
const bgqType = bgq.substring(bgq.length - 2)
const year = bgq.substring(0, 4) + '年'
const month = function(bgq) {
if (bgq.substring(4, 5) === 0) {
return bgq.substring(5, 6) + '月'
}
return bgq.substring(4, 6) + '月'
}
const halfYear = function(bgq) {
if (bgq.substring(5, 6) === '1') {
return '上半年'
} else {
return '下半年'
}
}
const season = '第' + bgq.substring(5, 6) + '季度'
const actions = new Map([
['YY', [year]],
['MM', [year + month(bgq)]],
['HY', [year + halfYear(bgq)]],
['SS', [year + season]],
['OO', [bgq]],
['default', ['---']]
])
}
這種方法的聰明之處在于:將判斷條件作為對象的屬性名戴差,將處理邏輯作為對象的屬性值庐杨,通過對象屬性查找的方式來進行邏輯判斷,這種寫法特別適合一元條件判斷的情況招刨。
介紹第二種寫法前霎俩,我先和大家普及一下ES6中的Map對象和Object對象的區(qū)別:
- 一個對象通常都有自己的原型,所以一個對象總有一個"prototype"鍵。
- 一個對象的鍵只能是字符串或者Symbols打却,但一個Map的鍵可以是任意值杉适。
- 你可以通過size屬性很容易地得到一個Map的鍵值對個數(shù),而對象的鍵值對個數(shù)只能手動確認柳击。
function translate(bgq) {
const bgqType = bgq.substring(bgq.length - 2)
const year = bgq.substring(0, 4) + '年'
const month = function(bgq) {
if (bgq.substring(4, 5) === 0) {
return bgq.substring(5, 6) + '月'
}
return bgq.substring(4, 6) + '月'
}
const halfYear = function(bgq) {
if (bgq.substring(5, 6) === '1') {
return '上半年'
} else {
return '下半年'
}
}
const season = '第' + bgq.substring(5, 6) + '季度'
const bgqOptions = {
YY: year,
MM: year + month(bgq),
HY: year + halfYear(bgq),
SS: year + season,
OO: bgq,
default: '---'
}
return bgqOptions[bgqType] || bgqOptions.default
}
上面是一元判斷猿推,當你的邏輯升級為二元判斷時,你的判斷量會加倍捌肴,你的代碼量也會加倍蹬叭,這時怎么寫更清爽呢?
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客態(tài) master主態(tài)
* @param {number} status 活動狀態(tài):1 開團進行中 2 開團失敗 3 開團成功 4 商品售罄 5 有庫存未開團
*/
const onButtonClick = (identity,status)=>{
let action = actions.get(`${identity}_${status}`) || actions.get('default')
action.call(this)
}
上述代碼核心邏輯是:把兩個條件拼接成字符串哭靖,并通過以條件拼接字符串作為鍵具垫,以處理函數(shù)作為值的Map對象進行查找并執(zhí)行,這種寫法在多元條件判斷時候尤其好用试幽。
當然上述代碼如果用Object對象來實現(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)
}
如果有些同學覺得把查詢條件拼成字符串有點別扭筝蚕,那還有一種方案,就是用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))
}
是不是又高級了一點點起宽?
這里也看出來Map與Object的區(qū)別,Map可以用任何類型的數(shù)據(jù)作為key济榨。
我們現(xià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 */}],
//...
])
好一點的寫法是將處理邏輯函數(shù)進行緩存:
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)能滿足日常需求了腐晾,但認真一點講,上面重寫了4次functionA還是有點不爽丐一,假如判斷條件變得特別復雜藻糖,比如identity有3種狀態(tài),status有10種狀態(tài)库车,那你需要定義30條處理邏輯巨柒,而往往這些邏輯里面很多都是相同的,這似乎也是筆者不想接受的柠衍,那可以這樣實現(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ā)送一個日志埋點,不同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))
}
也就是說利用數(shù)組循環(huán)的特性禽最,符合正則條件的邏輯都會被執(zhí)行腺怯,那就可以同時執(zhí)行公共邏輯和單獨邏輯,因為正則的存在川无,你可以打開想象力解鎖更多的玩法呛占,本文就不贅述了。
總結(jié)
本文已經(jīng)教你了6種優(yōu)雅的邏輯判斷寫法懦趋,包括:
- 一元判斷時:存到Object里
- 一元判斷時:存到Map里
- 多元判斷時:將condition拼接成字符串存到Object里
- 多元判斷時:將condition拼接成字符串存到Map里
- 多元判斷時:將condition存為Object存到Map里
- 多元判斷時:將condition寫作正則存到Map里
看完本文晾虑,我相信你也能優(yōu)雅的處理JS 的復雜判斷了