程式碼簡潔之道(判斷篇)
第一個例子
if (state === 1) {
return true
} else if (state === 2) {
return true
} else if (state === 3) {
return true
} else if (state === 4){
return true
} else {
return false
}
你首先想到的可能是 使用 switch case, 我們使用 switch case 來改寫它:
switch (state) { case 1: return true break; case 2: return true break; case 3: return true break case 4: return true break default: return false break }
看起來有些條理了, 但我們應對這類情況,可以將他進一步優化,觀察發現:
- 都是判斷 state
- 判斷後都做了相同的事情 (return true)
我們用 Array.includes 來優化它:
includes()
方法用來判斷一個數組是否包含一個指定的值,如果是返回 true,否則false。
- 引數一:必須。需要查詢的元素值。
- 引數二:可選。從該索引處開始查詢 searchElement。如果為負值,則按升序從 array.length + fromIndex 的索引開始搜尋。預設為 0。
const states = [1, 2, 3, 4] if (states.includes(state) { return true }
這樣是不是更簡單,程式碼量也更少了,同時也方便管理 states, 因為現在所有 state 都被加到 一個數組 (states) 了。
如果不是做相同的事情呢(即每一種狀態下我們需要做不同的事情)?例如下面這種情況:
if (state === 1) { // do something } else if (state === 2) { // do something } else if (state === 3) { // do something } else if (state === 4){ // do something } else { // do something }
我們可以使用物件來優化它:
const actions = {
1: () => { /*do something*/ },
2: () => { /*do something*/ },
3: () => { /*do something*/ },
4: () => { /*do something*/ },
'default': () => { /*do something*/ }
}
actions[state]() || actions['default']();
- 可讀性更高
- 更易於維護
原理很簡單,只需要通過物件的 key 找到物件的值, 而對應的值又是一個 func, 同時來執行它就可以了。
第二個例子
if (type === 'firstType') {
if (state === 1) {/*do something*/
// do something
} else if (state === 2) {
// do something
} else if (state === 3) {
// do something
} else if (state === 4){
// do something
} else {
// do something
}
} else if (type === 'secondType') {
if (state === 1) {
// do something
} else if (state === 2) {
// do something
} else if (state === 3) {
// do something
} else if (state === 4){
// do something
} else {
// do something
}
}
觀察上面的程式碼,發現外層又套了一層判斷,這在日常業務中也是十分常見的,例如一個 APP 需要區分不同身份,或者多端應用中。。。
仿照上面的例子稍加變動我們就能將它優化:
const actions = {
'firstType_1': ()=>{ /*do something*/ }],
'firstType_2': ()=>{ /*do something*/ }],
'firstType_3': ()=>{ /*do something*/ }],
'firstType_4': ()=>{ /*do something*/ }],
'secondType_1': ()=>{ /*do something*/ }],
'secondType_2': ()=>{ /*do something*/ }],
'secondType_3': ()=>{ /*do something*/ }],
'secondType_4': ()=>{ /*do something*/ }],
'default': ()=>{ /*do something*/ }]
}
const action = actions[`${type}_${state}`] || actions['default']
我們給物件的 key 設定為一個字串,字串由兩個條件通過 _ (當然你可以隨意) 連結在一起,它所對應的值依然是一個 func 。
同時用兩個變數通過模板字串的形式連結在一起,實現與上個例子相同的效果。
我們還可以使用 Map 來優化它:
const actions = new Map([
['firstType_1', ()=>{ /*do something*/ }],
['firstType_2', ()=>{ /*do something*/ }],
['firstType_3', ()=>{ /*do something*/ }],
['firstType_4', ()=>{ /*do something*/ }],
['secondType_1', ()=>{ /*do something*/ }],
['secondType_2', ()=>{ /*do something*/ }],
['secondType_3', ()=>{ /*do something*/ }],
['secondType_4', ()=>{ /*do something*/ }],
['default', ()=>{ /*do something*/ }]
])
const action = actions.get(`${type}_${state}`) || actions.get('default')
Map 類似於物件,也是鍵值對的集合,但是“鍵”的範圍不限於字串,各種型別的值(包括物件)都可以當作鍵。
原理與上個是一樣的,不過是將物件的形式改為了 Map 的形式,發現這樣稍微複雜了一些,但是我們可以用它來處理更復雜的情況。
我們假設 firstType 中 state 為 1-3 都做相同的事,那麼可以這樣寫:
const actions = new Map([
['/^firstType_[1-3]$/', ()=>{ /*do something*/ }],
['firstType_4', ()=>{ /*do something*/ }],
// ...
['default', ()=>{ /*do something*/ }]
])
很顯然使用正則表示式能夠減少重複的程式碼, 也能帶來更多可能性,處理更復雜的情況。
如果對應的方法中出現大量邏輯程式碼,那麼我們可以將 actions 封裝為一個函式。進一步來優化它,:
const actions = () => {
const fn1 = () => {}
const fn2 = () => {}
return new Map([
['/^firstType_[1-3]$/', fn1],
['firstType_4', fn2],
// ...
])
}
這樣做的好處是把對應的邏輯抽離出來,更加方便日後維護,條理更加清晰。
參考資料:
- JavaScript複雜判斷的更優雅寫法
- 你所需要知道的程式碼整潔之道
- ECMAScript6入門-map---阮一峰