通過刪除“ if-else”語句來清理代碼

您可以在代碼中看到此按鈕的單擊邏輯:根據(jù)不同的活動狀態(tài)執(zhí)行兩件事,發(fā)送日志隱藏點(diǎn)并跳轉(zhuǎn)到相應(yīng)的頁面,您可以通過/*** Button click event* @param {number} status* Activity status: 1 in progress, 2 in failure, 3 out of stock, 4 in success, 5 system cancelled*/const onButtonClick = (status)=>{if(status == 1){sendLog('processing')jumpTo('IndexPage')}else if(status == 2){sendLog('fail')jumpTo('FailPage')}else if(status == 3){sendLog('fail')jumpTo('FailPage')}else if(status == 4){sendLog('success')jumpTo('SuccessPage')}else if(status == 5){sendLog('cancel')jumpTo('CancelPage')}else {sendLog('other')jumpTo('Index')}}
swtich輕松地提出對此代碼的重寫。好吧,它看起來比if / else清楚得多,細(xì)心的讀者可能還會發(fā)現(xiàn)一個小技巧:情況2和情況3的邏輯相同,我們可以保存執(zhí)行語句并中斷,情況2將按照情況3的邏輯自動執(zhí)行。但是有一種更簡單的編寫方法。const onButtonClick = (status)=>{switch (status){case 1:sendLog('processing')jumpTo('IndexPage')breakcase 2:case 3:sendLog('fail')jumpTo('FailPage')breakcase 4:sendLog('success')jumpTo('SuccessPage')breakcase 5:sendLog('cancel')jumpTo('CancelPage')breakdefault:sendLog('other')jumpTo('Index')break}}
上面的代碼看上去確實(shí)更簡潔,這種方法的聰明之處在于它使用判斷條件作為對象的屬性名稱,并使用處理邏輯作為對象的屬性值。當(dāng)單擊按鈕時,此方法特別適用于一元條件判斷的情況,該條件通過對象屬性查找進(jìn)行邏輯判斷。很好,但是還有另一種編碼方式嗎?const actions = {'1': ['processing','IndexPage'],'2': ['fail','FailPage'],'3': ['fail','FailPage'],'4': ['success','SuccessPage'],'5': ['cancel','CancelPage'],'default': ['other','Index'],}const onButtonClick = (status)=>{let action = actions[status] || actions['default'],logName = action[0],pageName = action[1]sendLog(logName)jumpTo(pageName)}
是!
使用Map代替Object有很多優(yōu)點(diǎn),我們將在后面討論。Map對象和普通對象之間有什么區(qū)別?const actions = new Map([[1, ['processing','IndexPage']],[2, ['fail','FailPage']],[3, ['fail','FailPage']],[4, ['success','SuccessPage']],[5, ['cancel','CancelPage']],['default', ['other','Index']]])const onButtonClick = (status)=>{let action = actions.get(status) || actions.get('default')sendLog(action[0])jumpTo(action[1])}
一個對象通常有自己的原型,所以一個對象總是有一個“原型”鍵,除非我們使用Object.create(null)創(chuàng)建一個沒有原型的對象;
對象的鍵只能是字符串或符號,但是Map的鍵可以是任何值。
您可以通過使用size屬性輕松獲得Map中的鍵/值對數(shù)量,而對象中的鍵/值對數(shù)量只能手動確認(rèn)。
從上面的示例中可以看到,當(dāng)邏輯升級為雙重判斷時,判斷增加了一倍,代碼也增加了一倍。我們?nèi)绾尾拍芨逦鼐帉懘a?這是一個解決方案:/*** Button click event* @param {number} status* Activity status: 1 in progress, 2 in failure, 3 out of stock, 4 in success, 5 system cancelled** @param {string} identity: guest, master*/const onButtonClick = (status,identity)=>{if(identity == 'guest'){if(status == 1){//do sth}else if(status == 2){//do sth}else if(status == 3){//do sth}else if(status == 4){//do sth}else if(status == 5){//do sth}else {//do sth}}else if(identity == 'master') {if(status == 1){//do sth}else if(status == 2){//do sth}else if(status == 3){//do sth}else if(status == 4){//do sth}else if(status == 5){//do sth}else {//do sth}}}
以上代碼的核心邏輯是:將兩個判斷條件拼接成一個字符串作為Map的鍵,然后在查詢過程中直接搜索對應(yīng)字符串的值。當(dāng)然,我們也可以在這里將Map更改為Object: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*/}],])const onButtonClick = (identity,status)=>{let action = actions.get(`${identity}_${status}`) || actions.get('default')action.call(this)}
如果讀者發(fā)現(xiàn)將查詢拼寫為字符串有點(diǎn)笨拙,那么還有另一種解決方案,即使用Map對象作為鍵:const actions = {'guest_1':()=>{/*do sth*/},'guest_2':()=>{/*do sth*/},//....}const onButtonClick = (identity,status)=>{let action = actions[`${identity}_${status}`] || actions['default']action.call(this)}
加點(diǎn)難度。如果在來賓情況下status1-4處理邏輯相同怎么辦?最壞的情況是: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))}
更好的方法是緩存處理邏輯功能: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 */}],//...])
這足以滿足日常需求,但嚴(yán)重的是,將函數(shù)A覆蓋四次仍然有點(diǎn)煩人。如果事情變得非常復(fù)雜,例如身份具有3個狀態(tài),狀態(tài)具有10個狀態(tài),則需要定義30個處理邏輯,其中許多是相同的,這似乎是不可接受的。您可以這樣做: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))}
使用Map而不是Object的優(yōu)勢更加明顯,因?yàn)镽egular類型可以用作鍵。如果要求變?yōu)椋核衼碣e情況都需要發(fā)送日志掩埋點(diǎn),而不同狀態(tài)情況需要單獨(dú)的邏輯處理,那么我們可以編寫如下: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))}
也就是說,利用數(shù)組循環(huán)的屬性,將執(zhí)行任何符合常規(guī)條件的邏輯,從而可以同時執(zhí)行公共邏輯和單個邏輯。結(jié)論本文教了您八種編寫邏輯判斷的方法,包括: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))}
if/else
switch
一元判斷:存儲在Object中
一元判斷:保存到Map
多重判斷:將條件連接成字符串并將其保存在Object中
多重判斷:將條件連接成字符串并將其存儲在Map中
多重判斷:將條件另存為Map中的對象
多重判斷:將條件另存為Map中的正則表達(dá)式
評論
圖片
表情
