有一再有二,有二再有三。把未知的變成已知,就成了本身的知識javascript
好久以前,發了一篇文章:[淺析]特定場景下取代if-else和switch的方案,可是關於使用 if-else 的場景可不會僅僅是上面文章那麼少,還有不少的場景,今天再次寫下在開發上有哪些能夠代替或者優化 if-else
的場景。java
這裏強調代替或者優化
if-else
,是在特定場景下進行的。目的就是爲了在特定場景下改善代碼,讓代碼簡潔。增長代碼的可讀性,維護性,複用性。若是if-else
使用的場景比較簡單,或者代替,優化if-else
後會對代碼產生很差的影響。就不建議使用別的方案代替或者優化,不能爲了避免寫if-else
而不寫,不能爲了優化而優化。git
好比抽取中獎的號碼區間,中獎的號碼區間分別是 9-12,14-18,而後須要判斷號碼是否中獎了,邏輯很簡單就實現了github
let num1= 15
let num2= 13
if((num1>=9 && num1<=12)||(num1>=14 && num1<=18)){
// 中獎了
}
if((num2>=9 && num2<=12)||(num2>=14 && num2<=18)){
// 中獎了
}
複製代碼
這樣寫貌似沒什麼問題,若是之後需求變了,中獎的號碼不是9-12或者14-18。而是 10-14 或者 18-20。這樣就要改原來的代碼邏輯數組
if((num1>=10 && num1<=14)||(num1>=18 && num1<=20)){
// 中獎了
}
複製代碼
或者又有其餘需求,好比中獎號碼是 9-12,14-18,20-22或者26-30。仍是要改動一下 if-else 的邏輯微信
if((num1>=9 && num1<=12)||(num1>=14 && num<=18)||(num1>=20 && num1<=22)||(num2>=26 && num1<=30)){
// 數字在範圍內
}
複製代碼
如今能夠用some 進行封裝一個函數,只須要一次封裝,日後的需求若是範圍區間改變了,就能夠函數
function handleCheckRange(num, ...ranges){
return ranges.some(item=>num>=item[0]&&num<=item[1])
}
handleCheckRange(num1,[9,12],[14,18]) //true
handleCheckRange(num2,[9,12],[14,18]) //false
handleCheckRange(num2,[10,14],[18,20]) //true
handleCheckRange(num2,[9,12],[14,18],[20,22],[26,30]) //false
複製代碼
1.可能有人會想到若是再有需求,判斷條件不是 >= 或者 <= 。多是 < 和 >,<= 和 >,或者 < 和 >=呢?這樣
handleCheckRange
也是須要改了。這種狀況確實,遇到其餘的判斷條件是須要改一下這個方法。可是改一下這個方法並不難,直接封裝就好post2.若是判斷條件太多變化,必定要封裝方法兼容其餘的判斷條件,能夠參考個人筆記:練習題5:模擬實現開閉區間,這裏就不展開講了。優化
相信你們都會遇到可能會有多個條件組合的問題ui
好比有一個參與熱賣活動贈積分活動,活動狀態(status
),預熱中(status=1
),進行中(status=2
)。用戶類型(type
)也有分普通用戶(type=1
)vip用戶(type=2
)
規則是: 1.在預熱中參與活動,vip用戶贈送 1000 積分,普通用戶贈送 700 積分。 1.在進行中參與活動,vip用戶贈送 800 積分,普通用戶贈送 300 積分。
以前寫法是
let status=1
let type=2
if(status===1){
if(type===1){
console.log('普通用戶在預售中參與活動,贈送700積分')
}
else if(type===2){
console.log('vip用戶在預售中參與活動,贈送1000積分')
}
}
else if(status===2){
if(type===1){
console.log('普通用戶在進行中參與活動,贈送300積分')
}
else if(type===2){
console.log('vip用戶在進行中參與活動,贈送800積分')
}
}
// 或者
if(status===1&&type===1){
console.log('普通用戶在預售中參與活動,贈送700積分')
}
else if(status===1&&type===2){
console.log('vip用戶在預售中參與活動,贈送1000積分')
}
else if(status===2&&type===1){
console.log('普通用戶在進行中參與活動,贈送300積分')
}
else if(status===2&&type===2){
console.log('vip用戶在進行中參與活動,贈送800積分')
}
複製代碼
可是如今可使用 obj寫法,這樣下來,若是之後有什麼條件改了,直接改 obj 這個配置就好。
let obj={
'status=1&type=1':'普通用戶在預售中參與活動,贈送700積分',
'status=1&type=2':'vip用戶在預售中參與活動,贈送1000積分',
'status=2&type=1':'普通用戶在進行中參與活動,贈送300積分',
'status=2&type=2':'普通用戶在進行中參與活動,贈送800積分'
}
console.log(obj[`status=${status}&type=${type}`])
複製代碼
好比輸入一個城市名字,輸出一個省份名稱
let city='廣州'
if(city==='廣州'||city==='佛山'){
console.log('廣東')
}
else if(city==='海口'||city==='三亞'){
console.log('海南')
}
複製代碼
這樣寫的弊端就是,若是 if-else
數量一多,代碼就會多,並且判斷的條件會變得很長,還有一個問題就是風格有可能不會統一
下面用其餘方法進行優化下 方法一
let arr=[
{
city:'廣州',
province:'廣東'
},
{
city:'佛山',
province:'廣東'
},
{
city:'海口',
province:'海南'
},
{
city:'三亞',
province:'海南'
}
]
console.log(arr.filter(item=>item.city===city)[0].province)//廣東
複製代碼
方法二
let city='廣州'
let obj={
'廣州':'廣東',
'佛山':'廣東',
'海口':'海南',
'三亞':'海南',
}
console.log(obj[city])// 廣東
複製代碼
見到 廣東 和 海南 寫了這麼屢次,可能你們都會鬱悶,一個省城市有 20 個,就要寫 20 次,可能就有人會想到把城市都做爲 key
,而後判斷傳進來的 city
是否在 key
裏面,代碼以下。
let city='廣州'
let obj={
'廣州,佛山':'廣東',
'海口,三亞':'海南',
}
for(let key in obj){
if(key.includes(city)){
console.log(obj[key])
break
}
}
//廣東
複製代碼
可是弊端也出來了,就是上面的方法有 bug
,只輸出城市名稱的其中一個字,也能輸出對應的省份。
let city='州'
let obj={
'廣州,佛山':'廣東',
'海口,三亞':'海南',
}
for(let key in obj){
if(key.includes(city)){
console.log(obj[key])
break
}
}
//廣東
複製代碼
要解決這個問題,兩個方式,一種是把 key
轉成數組再判斷,或者使用 Map
// 方式一:把 key 轉成數組再判斷
let city='廣州'
let obj={
'廣州,佛山':'廣東',
'海口,三亞':'海南',
}
let keys=[]
for(let key in obj){
keys=key.split(',')
if(keys.includes(city)){
console.log(obj[key])
break
}
}
// 方式二:使用Map
let city='廣州'
let map=new Map([
[['廣州','佛山'],'廣東'],
[['海口','三亞'],'海南'],
])
for (let key of map.keys()) {
if(key.includes(city)){
console.log(obj[key])
break
}
}
//廣東
複製代碼
這樣狀況就是 if-elseif
沒什麼規則可尋。好比有需求是學生評選獎學金候選人活動
1.學生綜合素質得分(quality>=90
)90 以上,平均績點 4.5 以上,成爲一等獎學金候選人。
2.學生綜合素質得分 80 以上(quality>=80
),每科績點均不低於 2.5 ,成爲二等獎學金候選人。
3.學生綜合素質得分不低於 75(quality>=75
),得到過其餘獎項榮譽,成爲三等獎學金候選人。
let studentInfo={
name:'守候',
chinese:4.6,
math:4.7,
english:4,
computer:4.8,
quality:93,
prizes:['搬磚','掃地']
}
let subjectAll=['chinese','math','english','computer']
function handle (student,subject) {
function getAverage(){
let sum=0
subject.forEach(item=>sum+=student[item])
return sum/subject.length
}
function checkScore(){
return subject.every(item => student[item]>2.5)
}
if(student.quality>=90&&getAverage()>4.5){
console.log('成爲一等獎學金候選人')
// 其餘代碼
}
else if(student.quality>=80&&checkScore()){
console.log('成爲二等獎學金候選人')
// 其餘代碼
}
else if(student.quality>=75&&student.prizes.length>0){
console.log('成爲三等獎學金候選人')
// 其餘代碼
}
}
handle(studentInfo,subjectAll) //成爲一等獎學金候選人
複製代碼
代碼看着很簡單就完成了,可是實際開發中,if-elseif
的層級數量,每個 if-elseif
判斷邏輯和裏面的執行操做的代碼會遠超過這個例子。那麼 handle
這個方法的代碼會很長,方法會變得巨大。對代碼的可讀性,維護性,複用性都有不少影響。若是需求有變更,還須要把整個函數的邏輯都理清楚。
上面的代碼主要仍是要處理好 if-elseif
。可是這些 if-else
並無規矩可尋,因此只能所有都單獨抽取出來,全部的都封裝成函數。
function handle (student,subject) {
function getAverage(){
let sum=0
subject.forEach(item=>sum+=student[item])
return sum/subject.length
}
function checkScore(){
return subject.every(item => student[item]>2.5)
}
let rules=[
{
rule(){
return student.quality>=90&&getAverage()>4.5
},
fn(){
console.log('成爲一等獎學金候選人')
// 其餘代碼
}
},
{
rule(){
return student.quality>=80&&checkScore()
},
fn(){
console.log('成爲二等獎學金候選人')
// 其餘代碼
}
},
{
rule(){
return student.quality>=75&&student.prizes.length>0
},
fn(){
console.log('成爲三等獎學金候選人')
// 其餘代碼
}
}
]
for(let item of rules){
if(item.rule()){
item.fn()
// 執行完函數立刻返回,再也不執行下一次循環
return
}
}
}
複製代碼
這是隻要有 item.fn()
有執行到,說明該同窗已經成爲了候選人,把返回回來就好。
這樣一下,代碼也徹底符合 以前的 if-elseif
的邏輯。可能會有人有疑問,這樣一改代碼沒減小反而變多了,可是實際上,這個代碼已是分爲一塊一塊的,可讀性和維護性已經有所改善,若是須要有那裏改動,咱們也不須要理會整個函數,只須要改動 rules
。
還有一種狀況是,幾個 if-else
連着執行的代碼,
好比有一個頁面,能顯示用戶記錄的足跡,也可讓用戶選擇記錄本身的足跡,記錄的範圍能夠是省,是市,是區。那麼代碼就須要實現一個省市區,多選聯動。邏輯就是選了省,未必會選擇市,可是選了市就必然會選了省,以此類推。下面簡單寫一下僞代碼。
function initPostion(){
//全部省份列表
let provinceList=['廣東','廣西','海南','....']
//已選省份下轄的全部城市
let cityList=[]
//已選城市下轄的全部區
let districtList=[]
//已選擇省份
let selectedProvinces=['廣東','廣西']
//已選擇城市
let selectedCitys=['廣州']
//已選擇區
let selectedDistricts=['天河區']
//若是選了省份
if (selectedProvinces.length>0) {
//根據 selectedProvinces 獲取 cityList 的邏輯
//其餘代碼
}
if (selectedCitys.length>0) {
//根據 selectedCitys 獲取 districtList 的邏輯
//其餘代碼
}
//其餘初始化顯示的邏輯
}
複製代碼
僞代碼一寫,想必有開發者已經看出問題了。全部的 if
都耦合在一塊兒了, 並且 if 裏面的代碼邏輯可能會不少長。若是之後需求改了,要求選了國家,再選省市區,或者選擇區以後,還能選擇鎮和村。到時候 if
會變多,initPostion
總體代碼會變得巨大。維護起來會比較吃力,同時也容易出錯。
解決這問題,能夠把 if
拆分爲函數
function initPostion(){
//全部省份列表
let provinceList=['廣東','廣西','海南','....']
//已選省份下轄的全部城市
let cityList=[]
//已選城市下轄的全部區
let districtList=[]
//已選擇省份
let selectedProvinces=['廣東','廣西']
//已選擇城市
let selectedCitys=['廣州']
//已選擇區
let selectedDistricts=['天河區']
let handleObj={
provinces(){
//若是選了省份
if (selectedProvinces.length>0) {
//根據 selectedProvinces 獲取 cityList 的邏輯
//其餘代碼
}
},
city(){
if (selectedCitys.length>0) {
//根據 selectedCitys 獲取 districtList 的邏輯
//其餘代碼
}
}
}
let handleFns=['provinces','city']
for(let fnName of handleFns){
handleObj[fnName]()
}
//其餘初始化顯示的邏輯
}
複製代碼
可能這樣看着代碼是多了,可是管理起來會比原來的方案容易管理,每一塊 if
都被拆分爲一個函數,若是須要改動某一塊代碼,就改某一塊就好了,不須要對其餘的代碼進行改動。若是有需求上的變更,就是改 handleObj
的屬性函數,以及 handleFns
的順序就好了。
好了,關於 if-else
的代替和優化方案的第二篇文章到此爲止了。這裏再次強調,代替和優化 if-else
語句,建議是在特定場景下使用特定的方案進行。切記不能爲了代替而代替,不能爲了優化而優化。
若是以後還發現有另外的收穫會第一時間再寫文章。若是你們都該文章有什麼建議,見解,或者文章有什麼錯誤,改進的地方歡迎你們評論區留言
-------------------------華麗的分割線--------------------
想了解更多,和我交流,請添加我微信。或者關注個人微信公衆號:守候書閣