摘要:日后的維護可能存在問題。比如輸入一個景點,給出景點所在的城市。廣州塔廣州花城廣場廣州白云山廣州西湖杭州湘湖杭州京杭大運河杭州砂之船生活廣場杭州南宋御街杭州有些人不習慣對象的名是中文。小結最近在特定場合下,代替和的解決方案就是這么多了。
世界那么大,景點那么多。有些時候,換個方式,換個角度,換個陪同,都會有不一樣感覺與收獲。寫代碼也亦如此。1.前言
相信很多人有這樣的經歷,在項目比較忙的時候,都是先考慮實現,用當時以為最好的方式先實現方案,在項目不忙的時候,再看下以前代碼,想下有什么更好的實現方案,或者優化方案。筆者也不例外,下面就和讀者們分享一下自己最近在特定場合下,代替if-else,switch的解決方案。如果大家有什么想法,歡迎在評論區內留言,大家多多交流。
2.look-up表代替if-else比如大家可能會遇到類似下面的需求:比如某平臺的信用分數評級,超過700-950,就是信用極好,650-700信用優秀,600-650信用良好,550-600信用中等,350-550信用較差。
實現很簡單
function showGrace(grace) { let _level=""; if(grace>=700){ _level="信用極好" } else if(grace>=650){ _level="信用優秀" } else if(grace>=600){ _level="信用良好" } else if(grace>=550){ _level="信用中等" } else{ _level="信用較差" } return _level; }
運行也沒問題,但是問題也是有
1.萬一以后需求,改了比如650-750是信用優秀,750-950是信用極好。這樣就整個方法要改。
2.方法存在各種神仙數字:700,650,600,550。日后的維護可能存在問題。
3.if-else太多,看著有點強迫癥
所以下面用look-up表,把配數據置和業務邏輯分離的方式實現下
function showGrace(grace) { let graceForLevel=[700,650,600,550]; let levelText=["信用極好","信用優秀","信用良好","信用中等","信用較差"]; for(let i=0;i=graceForLevel[i]){ return levelText[i]; } } //如果不存在,那么就是分數很低,返回最后一個 return levelText[levelText.length-1]; }
這樣的修改,優點就是如果有需求修改,只需要修改graceForLevel,levelText。業務邏輯不需要改。
為什么這里推薦配數據置和業務邏輯分離1.修改配置數據比業務邏輯修改成本更小,風險更低
2.配置數據來源和修改都可以很靈活
3.薦配置和業務邏輯分離,可以更快的找到需要修改的代碼
如果還想靈活一些,可以封裝一個稍微通用一點的look-up函數。
function showGrace(grace,level,levelForGrace) { for(let i=0;i=level[i]){ return levelForGrace[i]; } } //如果不存在,那么就是分數很低,返回最后一個 return levelForGrace[levelForGrace.length-1]; } let graceForLevel=[700,650,600,550]; let levelText=["信用極好","信用優秀","信用良好","信用中等","信用較差"];
使用推薦配置數據和業務邏輯分離形式開發,還有一個好處,在上面例子沒體現出來,下面簡單說下。比如輸入一個景點,給出景點所在的城市。
function getCityForScenic(scenic) { let _city="" if(scenic==="廣州塔"){ _city="廣州" } else if(scenic==="西湖"){ _city="杭州" } return _city; }
輸入廣州塔,就返回廣州。輸入西湖就返回杭州。但是一個城市不止一個景點,那么有人習慣這樣寫。
if(scenic==="廣州塔"||scenic==="花城廣場"||scenic==="白云山"){ _city="廣州" }
如果景點很多,數據很長,看著難受,有些人喜歡這樣寫
let scenicOfHangZhou=["西湖","湘湖","砂之船生活廣場","京杭大運河","南宋御街"] if(~scenicOfHangZhou.indexOf(scenic)){ _city="杭州" }
這樣執行沒錯,但是寫出來的代碼可能像下面這樣,風格不統一。
function getCityForScenic(scenic) { let _city=""; let scenicOfHangZhou=["西湖","湘湖","砂之船生活廣場","京杭大運河","南宋御街"]; if(scenic==="廣州塔"||scenic==="花城廣場"||scenic==="白云山"){ _city="廣州" } else if(~scenicOfHangZhou.indexOf(scenic)){ _city="杭州" } return _city; }
即使用switch,也有可能出現這樣的情況
function getCityForScenic(scenic) { let _city=""; let scenicOfHangZhou=["西湖","湘湖","砂之船生活廣場","京杭大運河","南宋御街"]; switch(true){ case (scenic==="廣州塔"||scenic==="花城廣場"||scenic==="白云山"):_city="廣州";break; case (!!~scenicOfHangZhou.indexOf(scenic)):return "杭州"; } return _city; }
雖然上面的代碼出現的概率很小,但畢竟會出現。這樣的代碼可能會造成日后維看得眼花繚亂。如果使用了配置數據和業務邏輯分離,那就可以避免這個問題。
function getCityForScenic(scenic) { let cityConfig={ "廣州塔":"廣州", "花城廣場":"廣州", "白云山":"廣州", "西湖":"杭州", "湘湖":"杭州", "京杭大運河":"杭州", "砂之船生活廣場":"杭州", "南宋御街":"杭州", } return cityConfig[scenic]; }
有些人不習慣對象的 key 名是中文。也可以靈活處理
function getCityForScenic(scenic) { let cityConfig=[ { scenic:"廣州塔", city:"廣州" }, { scenic:"花城廣場", city:"廣州" }, { scenic:"白云山", city:"廣州" }, { scenic:"西湖", city:"杭州" }, { scenic:"湘湖", city:"杭州" }, { scenic:"京杭大運河", city:"杭州" }, { scenic:"砂之船生活廣場", city:"杭州" } ] for(let i=0;i這樣一來,如果以后要加什么景點,對應什么城市,只能修改上面的cityConfig,業務邏輯不需要改,也不能改。代碼風格上面就做到了統一。
這里簡單總結下,使用配置數據和業務邏輯分離的形式,好處
修改配置數據比業務邏輯修改成本更小,風險更低
配置數據來源和修改都可以很靈活
配置和業務邏輯分離,可以更快的找到需要修改的代碼
配置數據和業務邏輯可以讓代碼風格統一
但是并不是所有的if-else都建議這樣改造,有些需求不建議使用look-up改造。比如if-else不是很多,if判斷的邏輯不統一的使用,還是建議使用if-else方式實現。但是神仙數字,要清除。比如下面這個根絕傳入時間戳,顯示評論時間顯示的需求,
發布1小時以內的評論:x分鐘前
發布1小時~24小時的評論:x小時前
發布24小時~30天的評論:x天前
發布30天以上的評論:月/日
去年發布并且超過30天的評論:年/月/日
實現不難,幾個if-else就行了
function formatDate(timeStr){ //獲取當前時間戳 let _now=+new Date(); //求與當前的時間差 let se=_now-timeStr; let _text=""; //去年 if(new Date(timeStr).getFullYear()!==new Date().getFullYear()&&se>2592000000){ _text=new Date(timeStr).getFullYear()+"年"+(new Date(timeStr).getMonth()+1)+"月"+new Date(timeStr).getDate()+"日"; } //30天以上 else if(se>2592000000){ _text=(new Date(timeStr).getMonth()+1)+"月"+new Date(timeStr).getDate()+"日"; } //一天以上 else if(se>86400000){ _text=Math.floor(se/86400000)+"天前"; } //一個小時以上 else if(se>3600000){ _text=Math.floor(se/3600000)+"小時前"; } //一個小時以內 else{ //如果小于1分鐘,就顯示1分鐘前 if(se<60000){se=60000} _text=Math.floor(se/60000)+"分鐘前"; } return _text; }運行結果沒問題,但是也存在一個問題,就是這個需求有神仙數字:2592000000,86400000,3600000,60000。對于后面維護而言,一開始可能并不知道這個數字是什么東西。
所以下面就消滅神仙數字,常量化
function formatDate(timeStr){ //獲取當前時間戳 let _now=+new Date(); //求與當前的時間差 let se=_now-timeStr; const DATE_LEVEL={ month:2592000000, day:86400000, hour:3600000, minter:60000, } let _text=""; //去年 if(new Date(timeStr).getFullYear()!==new Date().getFullYear()&&se>DATE_LEVEL.month){ _text=new Date(timeStr).getFullYear()+"年"+(new Date(timeStr).getMonth()+1)+"月"+new Date(timeStr).getDate()+"日"; } //一個月以上 else if(se>DATE_LEVEL.month){ _text=(new Date(timeStr).getMonth()+1)+"月"+new Date(timeStr).getDate()+"日"; } //一天以上 else if(se>DATE_LEVEL.day){ _text=Math.floor(se/DATE_LEVEL.day)+"天前"; } //一個小時以上 else if(se>DATE_LEVEL.hour){ _text=Math.floor(se/DATE_LEVEL.hour)+"小時前"; } //一個小時以內 else{ //如果小于1分鐘,就顯示1分鐘前 if(se運行結果也是正確的,代碼多了,但是神仙數字沒了。可讀性也不差。
這里也順便提一下,如果硬要把上面的需求改成look-up的方式,代碼就是下面這樣。這樣代碼的修改的擴展性會強一些,成本會小一些,但是可讀性不如上面。取舍關系,實際情況,實際分析。function formatDate(timeStr){ //獲取當前時間戳 let _now=+new Date(); //求與當前的時間差 let se=_now-timeStr; let _text=""; //求上一年最后一秒的時間戳 let lastYearTime=new Date(new Date().getFullYear()+"-01-01 00:00:00")-1; //把時間差添加進去(當前時間戳與上一年最后一秒的時間戳的差)添加進去,如果時間差(se)超過這個值,則代表了這個時間是上一年的時間。 //DATE_LEVEL.unshift(_now-lastYearTime); const DATE_LEVEL={ month:2592000000, day:86400000, hour:3600000, minter:60000, } let handleFn=[ { time:DATE_LEVEL.month, fn:function(timeStr){ return (new Date(timeStr).getMonth()+1)+"月"+new Date(timeStr).getDate()+"日"; } }, { time:DATE_LEVEL.day, fn:function(timeStr){ return Math.floor(se/DATE_LEVEL.day)+"天前"; } }, { time:DATE_LEVEL.hour, fn:function(timeStr){ return Math.floor(se/DATE_LEVEL.hour)+"小時前"; } }, { time:DATE_LEVEL.minter, fn:function(timeStr){ return Math.ceil(se/DATE_LEVEL.minter)+"分鐘前"; } } ]; //求上一年最后一秒的時間戳 let lastYearTime=new Date(new Date().getFullYear()+"-01-01 00:00:00")-1; //把時間差(當前時間戳與上一年最后一秒的時間戳的差)和操作函數添加進去,如果時間差(se)超過這個值,則代表了這個時間是上一年的時間。 handleFn.unshift({ time:_now-lastYearTime, fn:function(timeStr){ if(se>DATE_LEVEL.month){ return new Date(timeStr).getFullYear()+"年"+(new Date(timeStr).getMonth()+1)+"月"+new Date(timeStr).getDate()+"日"; } }, }); let result=""; for(let i=0;i3.配置對象代替switch=handleFn[i].time){ result=handleFn[i].fn(timeStr); if(result){ return result; } } } //如果發布時間小于1分鐘,之際返回1分鐘 return result="1分鐘前" } 比如有一個需求:傳入cash,check,draft,zfb,wx_pay,對應輸出:現金,支票,匯票,支付寶,微信支付。
需求也很簡單,就一個switch就搞定了
function getPayChanne(tag){ switch(tag){ case "cash":return "現金"; case "check":return "支票"; case "draft":return "匯票"; case "zfb":return "支付寶"; case "wx_pay":return "微信支付"; } }但是這個的硬傷還是和上面一樣,萬一下次又要多加一個如:bank_trans對應輸出銀行轉賬呢,代碼又要改。類似的問題,同樣的解決方案,配置數據和業務邏輯分離。代碼如下。
function getPayChanne(tag){ let payChanneForChinese = { "cash": "現金", "check": "支票", "draft": "匯票", "zfb": "支付寶", "wx_pay": "微信支付", }; return payChanneForChinese[tag]; }同理,如果想封裝一個通用的,也可以的
let payChanneForChinese = { "cash": "現金", "check": "支票", "draft": "匯票", "zfb": "支付寶", "wx_pay": "微信支付", }; function getPayChanne(tag,chineseConfig){ return chineseConfig[tag]; } getPayChanne("cash",payChanneForChinese);這里使用對象代替 switch 好處就在于
使用對象不需要 switch 逐個 case 遍歷判斷。
使用對象,編寫業務邏輯可能更靈活
使用對象可以使得配置數據和業務邏輯分離。好處參考上一部分內容。
4.小結最近在特定場合下,代替if-else和switch的解決方案就是這么多了。if-else,switch本身沒錯,主要是想著怎么優化代碼,讓代碼更加具有可讀性,擴展性。如果大家還有什么優化的方案或者對方面的方案有更好的實現方案。歡迎在評論區留言。
-------------------------華麗的分割線--------------------
想了解更多,關注關注我的微信公眾號:守候書閣
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/96147.html
摘要:大多數情況下,對一個直接量和一個局部變量數據訪問的性能差異是微不足道的。 前端性能優化之 JavaScript 前言 本文為 《高性能 JavaScript》 讀書筆記,是利用中午休息時間、下班時間以及周末整理出來的,此書雖有點老舊,但談論的性能優化話題是每位同學必須理解和掌握的,業務響應速度直接影響用戶體驗。 一、加載和運行 大多數瀏覽器使用單進程處理 UI 更新和 JavaScri...
摘要:兩個例子比較而言,語句的實現可能更具兼容性,可以適應于數組元素是小數的情況。若數組元素為浮點類型,第二個例子就無法正常使用。開發環境推薦是基于瀏覽器的集成式開發環境,支持絕大部分編程語言,包括小程序等等,無需下載安裝程序,一鍵切換開發環境。 Coding Tip: Try to Code Without If-statements showImg(https://segmentfaul...
摘要:定義公共組件供各模塊或特定場景調用,復用度高第三方庫組件插件庫用于解決以下版本瀏覽器對新增標簽不識別,并導致不起作用的問題。 前端重構方案 前言 前端技術發展很快,很多項目面臨前端部分重構,很開心可以讓我進行這次項目前端的重構方案編寫,在思考的同時參考了網上很多資料,希望本篇重構方案有一定的完整性,可以帶給大家一些在面臨重構時有用的東西,同時希望路過的大牛小牛不領賜教,能給我略微指點...
摘要:表達式用來計算出一個值,語句用來執行以使某件事發生。其中,語句會立即退出循環,強制繼續執行循環后面的語句。在執行語句之后,結果顯示。語句語句的作用是指定函數調用后的返回值。語句語句的作用是把程序運行時產生的錯誤顯式地拋出異常。 表達式在 JavaScript 中是短語,那么語句就是整句命令。表達式用來計算出一個值,語句用來執行以使某件事發生。從本質上看,語句定義了 JavaScript...
閱讀 1830·2021-10-20 13:49
閱讀 1371·2019-08-30 15:52
閱讀 2876·2019-08-29 16:37
閱讀 1046·2019-08-29 10:55
閱讀 3079·2019-08-26 12:14
閱讀 1659·2019-08-23 17:06
閱讀 3243·2019-08-23 16:59
閱讀 2553·2019-08-23 15:42