JavaScript 中遇到複雜邏輯判斷時,通常用 switch
代替 if/else
。隨著邏輯複雜度增加,這兩種條件判斷方式都會變得臃腫、難明。本文旨在介紹一些優雅的條件判斷方式。
將判斷條件作為對象的鍵,處理行為作為相應值,再透過查找對象屬性的方式來作條件判斷——這種寫法尤適合一元條件判斷之情況,亦為眾所知:
const actions = {
'1': ['processing', 'IndexPage'],
'2': ['fail', 'FailPage'],
'3': ['fail', 'FailPage'],
'4': ['success', 'SuccessPage'],
'5': ['cancel', 'CancelPage'],
'default': ['other', 'IndexPage'],
}
/**
* 按鈕點擊事件
* @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)
}
ES2015 推出的 Map 對象,與 Object 對象之區別在於:
size
屬性輕易地得到一 Map 的鍵值對數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])
}
現在把問題升級一下,在判斷 status
的同時,還需要判斷用戶的身份。若用 if/else
或 switch
來寫,會非常囉嗦冗長;但用 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*/}],
])
/**
* 按鈕點擊事件
* @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 也是可行的。若嫌把查詢條件拼成字符串略顯彆扭,則還可用 Object 作鍵:
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))
}
再對需求作升級:identity 為 guest
的情況下,status 為 1-4
時的處理邏輯都一樣(即執行同一個函數)。可以這樣寫:
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))
}
上例重寫了 4 次 functionA
,而且假如判斷條件愈加複雜,需要定義的處理邏輯亦將增多。此時 Map 就顯出優勢了:可以使用正則類型作鍵。改寫如下:
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], // 甚至可作通配,實現凡是 guest 都要發送一日誌埋點
// ...
])
}
const onButtonClick = (identity, status)=>{
let action = [...actions()].filter(([key, value]) => (key.test(`${identity}_${status}`)))
action.forEach(([key, value])=>value.call(this))
}
完 :)