面對過多的if-else,代碼可能看起來比較冗餘,搞很差又是一張被人處處轉發的「咱們項目幾百幾千行if」的圖。可是通過各類設計模式和封裝,if大大減小,但可讀性可能稍微下降了,並且比較抽象。那咱們應該如何取捨呢前端
拋開其餘因素,若是if-else過多,可讀性也許會好也可能會下降,可維護性也是或高或低;若是if-else少,代碼高度抽象,可讀性會低或者不變,可維護性可能會高也可能會低。這裏大概可能會有幾種狀況設計模式
這種狀況,if精簡不精簡,可讀性是不會變的,可是精簡程度和可維護性是正相關的。至於爲何,看一下代碼就能夠感覺到了模塊化
if (a === 1) {
console.log('this is 1')
} else if (a === 2) {
console.log('this is 2')
} else if (a === 3) {
console.log('this is 3')
}
// ...還有不少
else {
console.log('this is other')
}
複製代碼
精簡代碼:函數
// 若是上面的if a是從1到10
console.log(`this is ${a > 0 && a < 10 ? a : 'other'}`)
// 若是上面的if a是從1到5和從7-10
if ((a > 0 && a < 5) || (a > 7 && a < 10) {
console.log(`this is ${a}`)
} else {
console.log('this is other')
}
// a取值靈活區間
const area = [[1,2], [5,7], [10, 11]]
console.log(`${area.find(([from, to]) => { return from <= a && a <= to }) ? a : 'other'}`)
複製代碼
這種狀況,有沒有精簡,可讀性都沒有發生變化,若是是未精簡的,寫一堆if,你仍是很容易看得出幹啥。而可維護性就不同了,要加一個或者多個數字,那麼就要深刻到某個if分支,一個個動手改,維護性低。可是,若是精簡了的話,維護性大大增長,代碼也簡短。只須要尋找if的規律並封裝全部的case便可,最後作到「條件驅動」學習
有一些很是簡單的狀況,可使用&&
、||
、三元解決優化
// before
if (cb) {
cb()
}
//after
cb && cb()
// before
if (!obj) {
obj = {}
}
obj.a = 1
//after
(obj || obj = {}).a = 1
// before
if (type === true) {
value = 1
} else {
value = 2
}
//after
value = type ? 1 : 2
// before
if (type === DEL) {
this.delateData(id)
} else {
this.addData(id)
}
// after
this[type === DEL ? 'delateData' : 'addData'](id)
// or
;(type === DEL ? this.delateData : this.addData)(id)
// before
if (a === 1 && a === 2 && a === 10) {
console.log('ok')
}
// after
if ([1, 2, 10].includes(a)) {
console.log('ok')
}
複製代碼
條件單1、執行語句單一的狀況,建議優化指數:★★★★★ui
if (a === 1) {
console.log('this is 1')
} else if (a === 2) {
console.log('this is 二')
} else if (a === 3) {
console.log('this is three')
}
// ...還有不少
else {
console.log('this is other')
}
複製代碼
精簡代碼:this
const map = {
1: 'this is 1',
2: 'this is 二',
3: 'this is three',
// ...不少
}
console.log(map[a] || 'this is other')
複製代碼
這種狀況,和執行語句單一相似,也是可讀性不變,代碼減小了可維護性只是略好一點。一般的解決辦法就是k-v映射了。加一個條件,就在map中加多一對k-v(因爲條件處理複雜,因此條件上沒有優化空間了,必須寫出來)spa
這種場景,平時應該會比較常見轉爲switch。若是執行語句很複雜無規律,寫k-v的缺陷就來了:一個key被迫對應一個callback函數,還會花時間斟酌傳值問題,並且代碼量也沒發生變化,此時不建議優化設計
if (a === 1) {
console.log('this is 1')
alert(a * 100);
} else if (a === 2) {
console.log('this is 二')
document.body.innerHTML = a + 1 + b
}
// after
const map = {
1: (a) => {
console.log('this is 1')
alert(a * 100);
},
2: (a, b) => {
console.log('this is 二')
document.body.innerHTML = a + 1 + b
}
}
map[a](a, b) // 代碼量並無減小也沒有加強維護性
複製代碼
問題來了,條件單一,但處理語句有簡單的也有複雜的怎麼辦?case by case,先歸類再分狀況,最終只會剩下少許if和switch的
小結: 條件單1、執行語句複雜的狀況,有規律時建議優化指數:★★★,無規律時,建議指數:★
若是條件複雜,執行語句單一,那麼條件能夠經過&&
、||
、三元來簡化,或者是平鋪if-return
,問題也迎刃而解。然而,條件複雜,執行語句大機率也是複雜的。
if (a === 1) {
console.log(1);
} else if (arr.length === 3) {
alert('this is length 3 arr');
} else if (a === 2 && b === 1) {
console.log(2);
console.info('haha');
} else if (a === 2) {
console.log(222);
document.title = 'a = 2';
} else if (arr.length) {
console.error('arr is not empty');
}
複製代碼
都沒有規律可循,那麼就真的沒有進一步方案了。可是咱們觀察一下,發現一些條件是有交集的,如a === x
,咱們能夠把這種類型的if抽出來:
const handleA = {
1: () => {
console.log(1);
},
2: () => {
if (b === 1) {
console.log(2);
console.info('haha');
} else {
console.log(222);
document.title = 'a = 2';
}
}
}
const handleArrLen = {
3: () => {
alert('this is length 3 arr');
}
}
if (handleA[a]) {
handleA[a]()
} else if (arr.length) {
;(handleArrLen[arr.length] || () => {
console.log(222);
document.title = 'a = 2';
})()
}
複製代碼
這樣子,能夠把邏輯模塊化,增長可讀性和可維護性,可是犧牲了精簡性。
注意,上面這樣子條件模塊化了,意味着同一類的條件都會歸到一塊兒。若是業務邏輯對if條件有嚴格要求的,好比必定要先判斷a === 1
,再看看arr.length === 3
,再看a === 2 && b === 1
,按照這樣的順序,那就不能這樣作了
還有一種狀況,就是if裏面直接調用已經封裝好的函數,沒有其餘語句(其實就至關於退化爲條件複雜,執行語句簡單了):
if (a === 1) {
f1()
} else if (arr.length === 3) {
f2()
} else if (a === 2 && b === 1) {
f3()
} else if (a === 2) {
f4()
} else if (arr.length) {
f5()
}
複製代碼
這種狀況(前提條件,不會常常改這裏,若是是常常改,仍是會吐血的),減小if後也不賴:
const index = [a === 1, arr.length === 3, a === 2 && b === 1, a === 2, arr.length].findIndex(Boolean)
if (index !== -1) {
[f1, f2, f3, f4, f5][index]()
}
複製代碼
若是全部的else if都是互斥的,沒有交集,那麼換成
if-return
更好
if (a) {
// do xx about a
return
}
if (b) {
// do xx about b
return
}
複製代碼
小結:若是條件複雜,執行語句單一,建議優化指數: ★★★★★;若是執行語句也複雜,當條件能夠模塊化的且沒有順序要求,建議優化指數: ★★★★。當條件有嚴格順序要求、無規律可循,不建議強行減小if-else
嵌套實際上就是平鋪的加強,平鋪嵌套平鋪,咱們能夠看成是多個if平鋪條件複雜的狀況來看。例若有以下代碼,咱們尋找一些規律來優化一下
if (id === 1) {
console.log(1);
if (type === 2) {
console.log('type2');
} else {
console.log('type3');
}
} else if (id === 2) {
console.log(2);
if (type === 3) {
console.log('id2 type3');
if (ext === 1) {
console.log('ext1');
}
}
} else {
console.log('other id');
}
複製代碼
根據id劃分:犧牲了其餘因素的可讀性,但對於id的維護性加強了
const handleId = {
1: () => {
console.log(1)
console.log(type === 2 ? 'type2' : 'type3')
},
2: () => {
console.log(2)
// 這裏建議優化指數爲★★,可能可讀性低,因此保持現狀也行
// eslint一開,這套涼涼,必須寫回普通if-else
type === 3 && (console.log('id2 type3'), ext === 1) && console.log('ext1')
}
}
handleId[type] ? handleId[type]() : console.log('other id')
複製代碼
若是此時根據type劃分,那麼難度大大增長了,這就是人人害怕的重構了。若是後面業務邏輯,的確是以type爲主導的,那重構也是遲早的事情了。因此,前期的設計以及產品邏輯,將會決定後面的維護舒服不舒服了
小結: if條件有嵌套狀況,拆分if,其實就是平鋪的if嵌套平鋪的if,若是有規律可循,那麼按照前面的平鋪來減小if。若是沒有規律、也不是邏輯側重的點,那麼就不建議減小if了
if-else
來優化,用條件驅動結果(&& ||
三元或者是本身寫小邏輯)if-else
來優化;若是執行語句也複雜,當條件能夠模塊化的且沒有順序要求,比較建議優化。當條件有嚴格順序要求、無規律可循,不建議任何改動關注公衆號《不同的前端》,以不同的視角學習前端,快速成長,一塊兒把玩最新的技術、探索各類黑科技