基礎程式碼重構的若干建議(一)
提煉函式作為程式碼重構中常見的方式之一,是應該最被重視的。但我們程式中某些片段可以被獨立出來,那麼就建議將這部分獨立為一個函式,通過命名以及解耦的方式這端程式碼發揮更大的價值。最被提倡的函式是純函式。
提煉函式的主要優點:
- 避免出現超大函式
- 有利用程式碼複用
- 有利於問題排查
- 有利於函式的覆蓋
- 具有良好命名的函式容易被解讀,能起到較好的註釋作用
舉例:拼接使用者資訊
asyncgetUser = function() { var user = await Api.getUser() ; var {name, age, sex} = user ; var userInfo = `${name}:${age}歲,性別:${sex}`; } // 提煉函式 ,提煉之後的好處是與拼接使用者資訊的需求都獨立為函式,函式對外只依賴user物件 asyncgetUser = function() { var user = await Api.getUser() ; var userInfo = gerUserInfoMsg(user); } function gerUserInfoMsg (user){ var {name, age, sex} = user ; return`${name}:${age}歲,性別:${sex}`; } 複製程式碼
合併重複的程式碼段
如果一個程式碼段有大量的重複程式碼,尤其常見的是分支語句中有重複程式碼,有必要進行合併去重。
比如下面的案例:重複呼叫setState有一定規律的屬性賦值,重複的判斷一些type型別都可以進行合併去重。
setDropDownVisible = (type) => { if(type === 'vaild'){ this.setState({ vaildDropdown: true }) } if(type === 'sex'){ this.setState({ sexDropdown: true }) } if(type === 'age'){ this.setState({ ageDropdown: true }) } } // 優化後 setDropDownVisible = (type) => { const typeArr = ['vaild', 'sex', 'age']; if(typeArr.includes(type)){ this.setState({ [`${type}Dropdown`]: true }) return } console.warning(type + 'is not in stand type'); } 複製程式碼
條件分支語句提煉為函式
在複雜度較高的程式中會存在很多看似很複雜的條件判斷形成分支語句以及與這個條件有關的封裝程式碼段,如果某個條件構成良好的準則,可以將判斷條件進行封裝,讓邏輯更加清晰。
function getPrice(price,month){ if(!month) return ; if(month >= 6 && month <= 9 ) { return price * 0.8 } } // 其中 month >= 6 && month <= 9的程式碼含義是判斷是否處於夏季,提煉函式 function isSummer(month){ return month >= 6 && month <= 9 } function getPrice(price,month){ if(!month) return ; if(isSummer(month)) { return price * 0.8 } } 複製程式碼
合理使用迴圈
看似簡單的迴圈可以幫我們處理很多重複而簡單的程式碼以及過程,也可以讓維護更加簡單,讓程式碼更有規律。
render(){ return ( <select> <option value="1">第一季度</option> <option value="2">第二季度</option> <option value="3">第三季度</option> <option value="4">第四季度</option> </select> ) } // 上面的option明顯的可以用迴圈的方式來進行 render(){ const seasonArr = [ { value: 1, label: '第一季度' }, { value: 2, label: '第二季度' }, { value: 3, label: '第三季度' }, { value: 4, label: '第四季度' }, ]; return ( <select> {seasonArr.map(item) => (<option value={value} key={value}>{label}</option>)} </select> ) } 複製程式碼
提前讓函式退出
在我們書寫大多數函式的時候,很多人喜歡用一個返回關鍵變數控制結果,然後最後返回結果。其實這樣的書寫可以簡化為當得到結果時立即返回,一則邏輯更加清晰,減少了很多巢狀 ;二則 函式的執行效率更高。
function judgeAge(age){ var judgeResult = ''; if(age < 18){ judgeResult = '未成年' } else if(age < 30){ judgeResult = '青年' } else if(age < 50){ judgeResult = '中年' } else if(age < 100){ judgeResult = '老年' } return judgeResult; } // 改造後,判定結果收集,符合任何一個條件,馬上返回跳出函式 function judgeAge(age){ var judgeResultArr = ['未成年', '青年','中年', '老年']; if(age < 18){ return judgeResultArr[0] } if(age < 30){ return judgeResultArr[1] } if(age < 50){ return judgeResultArr[2] } if(age < 100){ return judgeResultArr[3] } } 複製程式碼
傳遞物件引數代替長引數列表
function person(age, sex, age, edu){ } // 引數改造後 function person(personObj){ } var personObj = { name:"zhangsan", sex: 'male', age: 12, } var zhangsan = new Person(personObj); 複製程式碼
分析函式特點,減少引數
需要將程式碼進行解析,是否有些引數是存在關聯的,可代替的,比如我們需要畫布設定一個正方形的div色塊,需要傳入寬高以及面積。
而經過分析之後,我們先確定需求,如果只需要畫正方形,那麼只需要傳入寬度,高度等於寬度不用傳,面積也可以通過計算得知。
function drawSquare(width, height, s){ } function drawSquare(width){ let height = width; let s = width * height; } 複製程式碼
避免使用過重的三目運算
三目運算可以解決的問題,需要返回一個結果值,並且沒有過多的邏輯判斷。如果你是需要邏輯與運算、或運算,可以直接採用熔斷寫法。
比如下面的,let sex = sex ? sex : 'male'
, 可以用let sex = sex || 'male'
,那麼就可以 更簡單;
同理,如果你希望基於存在的情況下去判斷執行語句,否則不執行邏輯 ,
比如jsx語法中:{isAble ? <button/> : null}
,直接寫成,{isAble && <button/>}
let patch = fs ? path ? fs(path) : fs('xxx') : null // 這種多餘兩層的邏輯判斷更建議大家寫if/else 實現 if(fs) { if(path){ } else { } } else { } 複製程式碼
合理使用鏈式呼叫
具體參照鏈的設計模式,做法很簡單,在方法執行完成後返回this,就可以實現鏈式的不斷呼叫執行方法,可以簡化大量的程式碼。
分解大型類
主要是將複雜的方法或者演算法或者具有典型特徵的物件進行肢解,讓其以組合的方式進行設計,不但進行了解耦,而且可以讓整體的架構可維護性更強。
return 跳出多重迴圈
因為for迴圈,尤其多層巢狀迴圈會佔用的大量的記憶體以及執行時間,如果在函式得到期望結果的時候,那麼就建議及時的跳出迴圈,避免效能的浪費。比如我們要寫一個Array.prototype.includes方法.
Array.prototype.includes = function (arr, key) =>{ if(Array.isArray(arr)) return false ; arr.forEach((item)=>{ if(item === key) { return true; } }) return false; } 複製程式碼