其實我們可以少寫點if else和switch

瀟湘待雨發表於2019-01-09

前言

作為搬磚在第一線的底層工人,業務場景從來是沒有做不到只有想不到的複雜。
不過他強任他強,if-else全搞定,搬就完了。但是隨著業務迭代或者專案交接,自己在看自己或者別人的if程式碼的時候,心情就不再表述了,各自深有體會。所以我們一起看看if還能怎麼寫

最基本if-else

假設有這麼個場景,不同情況下列印不同值。因為涉及到的條件太多,就不提三目運算之類優化了。

if (a == 1) { 
console.log('a1')
} else if (a == 2) {
console.log('b2')
} else if (a == 3) {
console.log('c3')
} else if (a == 4) {
console.log('d4')
}/* n..... */複製程式碼

現在還算能看,因為邏輯簡單,如果邏輯複雜,迭代多個版本之後,你還敢動嗎。
每動一下就戰戰兢兢,誰知道哪裡會遺漏。那麼換種方式呢

switch-case

這樣稍微清晰那麼一點,差別好像沒什麼差別:

switch(a){ 
case 1: console.log('a1');
break;
/* 省略。。。 */ case 40: console.log('a40');
break;

}複製程式碼

分離配置資訊與執行動作

object對映

定義一個object作為配置物件來存放不同狀態,通過連結串列查詢

const statusMap = { 
1:()=>
{
console.log('a1')
}, 2:()=>
{
console.log('b2')
} /* n.... */
}// 執行let a = 1 statusMap[a || 1]()複製程式碼

這樣比較清晰,將條件配置與具體執行分離。如果要增加其他狀態,只修改配置物件即可。

陣列對映

當然在某些狀態下可以使用陣列,來做這個配置物件。

// 這裡就涉及其他優化了,例如將執行函式抽離出來,大家不要關注func的內容就好。// 它就是個function,內容很複雜const statusArr = [function(){ 
console.log(1)
}, function () {
console.log(2)
},]// 執行let a = 1statusArr[a || 1]()複製程式碼

陣列的要求更高一點,如果是其他key,例如字串,那麼陣列就不能滿足需求了

升級版:不同key相同value

這樣看起來好一點了,那麼需求又有變動了,
前面是每種處理方式都不同,下面有幾種情況下處理函式相同的,例如1-39的時候,呼叫a,40之後呼叫b,如果我們繼續來用對映的方式來處理。

function f1 (){ 
console.log(1)
}function f2 (){
console.log(2)
}const statusMap={
1:f1, 2:f1, 3:f1, 4:f1, //省略 40:f2
}let a = 2statusMap[a]()複製程式碼

這樣當然也可以,不過重複寫那麼多f1,程式碼看起來不夠簡潔。

開始重構之前我們先捋一下思路,無非是想把多個key合併起來,對應一個value。
也就是說我們的鍵值不是字串而是個陣列,object顯然只支援字串,那麼可以將這麼多key合併成一個:’1,2,3,4,..,9’。

但是查詢的時候有點問題了,我們的引數肯定不能完全匹配。
接著走下去,是不是做個遍歷加個判斷,包含在子集內的都算匹配,那麼程式碼看起來就是下面這個樣子。

// 將鍵值key設定為一個拼接之後的字串const statusMap = { 
'1,2,3,4,5': f1, //省略 40: f2
}// 獲取所有的鍵值,待會遍歷用const keys = Object.keys(statusMap), len = keys.length// 遍歷獲取對應的值 const getVal=(param='')=>
{
// 用for迴圈的原因在於匹配之後就不需要繼續遍歷 for (let i = 0;
i <
len;
i++) {
const key = keys[i], val = statusMap[key] // 這裡用什麼來判斷就隨便了,兩個字串都有。 if (key.includes(param)) {
return val
}
}
}let a = 2, handle = getVal(a)handle() // 1複製程式碼

但是這樣來看,增加了個遍歷的過程,而且是拼接字串,萬一哪天傳了個逗號進來,會得到了預料之外的結果。

map

es6有個新的資料結構Map,支援任意資料結構作為鍵值。如果用Map可能更清晰一點。

/** * map鍵值索引的是引用地址, * 如果是下面這樣的寫法不好意思,永遠得不到值 * map1.set([1,4,5],'引用地址') * map1.get([1,4,5])  //輸出為undefined * 就像直接訪問 * map1.get([1,2,3,4,5]) //同樣為undefined */const map1 = new Map()const statusArr = [1,2,3,4,5]map1.set(statusArr,f1)// 預設預設值,因為不能直接遍歷let handle = function(){
}const getVal = (param = '') =>
{for (let value of map1.entries()) {
console.log(JSON.stringify(value)) if (value[0].includes(param)){
console.log(value) // 不能跳出 只能處理了 handle = value[1]
}
}
}const a = 2getVal(a)handle()複製程式碼

個人而言雖然這樣減少了重複程式碼,但是又增加了一步匹配值的操作,優劣就見仁見智吧。

雙陣列

肯定有部分人就是不想做遍歷的操作,既然一個陣列不能滿足,那麼兩個陣列呢。

// 鍵值陣列和value 保持對應關係const keyArr = ['1,2,3,4,5','40']const valArr = [f1,f2]const getVal = (param = '')=>
{
// 查詢引數對應的下標 let index = keyArr.findIndex((it)=>
{
return it.includes(param)
}) // 獲取對應值 return valArr[index]
}let a = 2, handle = getVal(a)handle()複製程式碼

利用陣列提供的下標,將key和value對應起來,進而獲取想要的值。
這裡一直沒有達到我最初的目的,即鍵裡面重複的陣列,可以不通過多餘操作匹配到,上面不管怎麼樣都進行了處理,這不是懶人的想要的。

總結

這是在寫業務需求的時候做的一點總結,陣列和物件的對映可能大家都在用。當遇到了不同key相同value的情況時,從懶出發不像重複羅列,就嘗試了下。當然了,因為個人水平問題,肯定有更好的處理方式,歡迎一起討論,拋磚引玉共同進步。此外現有成熟的庫裡loadsh也是可以到達目的,不過自己思考過之後再去看大神的作品理解會更深入一點。更多文章請轉我的部落格

來源:https://juejin.im/post/5c3607b1e51d4503834d3bd2

相關文章