重構你的 javascript 代碼
阿新 • • 發佈:2019-01-28
進行 中大 ESS cee stat ali 根據 char 檢測 近查閱較多js編碼指南以及重新閱讀了《代碼整潔之道》、《重構:改善既有代碼的設計》兩本經典書籍(強烈建議每隔一段時間看,每次都有新體會),整理出以下幾個要點,幫助大家以最小的記憶,重構大部分壞代碼。
壞代碼判斷
壞代碼對每個人、每個項目標準都不一樣,但以下幾點大概率會是壞代碼,需要使用重構方法進行代碼重構。
重復代碼
過長函數
過大的類
過長參數列表
重構方法
- 好的命名
好的命名貫穿整個軟件編碼過程,好命名包括合理使用大小寫定義、縮進等。目前前端工程提供很多lint或format工具,能很方便的幫助工程檢測和自動化,不清楚的同學可以看看筆者AI前端工具鏈。不管是變量名、函數名或是類名,一個好的命名會加快自身開發效率以及閱讀代碼效率,畢竟程序讀的次數會比寫的次數多的多。讀github上優秀源碼就知道,有時候只要看函數名就知道作者的意圖。
// bad
var yyyymmdstr = moment().format(‘YYYY/MM/DD‘);
// good
var yearMonthDay = moment().format(‘YYYY/MM/DD‘);
// bad function dateAdd(date, month) { // ... } let date = new Date(); dateAdd(date, 1) // 很難理解dateAdd(date, 1)是什麽意思。筆者註:這裏單拎出來舉例很簡單易懂,但希望在做工程時也時刻謹記這條 // good function dateAddMonth(date, month) { // ... } let date = new Date(); dateAddMonth(date, 1);
2. 函數單一職責
軟件工程中最重要原則之一。剛畢業不久的開發人員容易出現這個問題,覺得業務邏輯很復雜,沒辦法再細分成單獨函數,寫出很長的業務函數。但根據筆者指導小夥伴經驗,大多數是臨時變量過多,導致看不穿業務邏輯的本質;其實重構過程中一步步分解職責,拆分成細小函數並用恰當的名稱命名函數名,能很快理解業務的本質,說不定還能發現潛藏的bug。
// bad function handle(arr) { //數組去重 let _arr=[],_arrIds=[]; for(let i=0;i<arr.length;i++){ if(_arrIds.indexOf(arr[i].id)===-1){ _arrIds.push(arr[i].id); _arr.push(arr[i]); } } //遍歷替換 _arr.map(item=>{ for(let key in item){ if(item[key]===‘‘){ item[key]=‘--‘; } } }); return _arr; } // good function handle(arr) { let filterArr = filterRepeatById(arr) return replaceEachItem(filterArr) }
3. 通過引入解釋性變量或函數,使得表達更清晰
// bad
if (platform.toUpperCase().indexOf(‘MAC‘) > -1 && browser.toUpperCase().indexOf(‘IE‘) > -1 && wasInitialized() && resize > 0) {
// do something
}
// good
let isMacOs = platform.toUpperCase().indexOf(‘MAC‘) > -1
let isIEBrowser = browser.toUpperCase().indexOf(‘IE‘) > -1
let isResize = resize > 0
if (isMacOs && isIEBrowser && wasInitialized() && isResize) {
// do something
}
// bad
const cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/;
saveCityState(ADDRESS.match(cityStateRegex)[1], ADDRESS.match(cityStateRegex)[2]);
// good
var cityStateRegex = /^(.+)[,\\s]+(.+?)\s*(\d{5})?$/;
var match = ADDRESS.match(cityStateRegex)
let [, city, state] = match
saveCityState(city, state);
// bad
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * _winterRate + _winterServiceCharge
} else {
charge = quantity * _summerRate
}
// good
if (notSummer(date)) {
charge = winterCharge(quantity)
} else {
charge = summerCharge(quantity)
}
4. 更少的嵌套,盡早 return
// bad
let getPayAmount = () => {
let result
if (_isDead) result = deadAmount()
else {
if (_isSeparated) result = separatedAmount()
else {
if (_isRetired) result = retiredAmount()
else result = normalPayAmount()
}
}
return result
}
// good
let payAmount = () => {
if (_isDead) return deadAmount()
if (_isSeparated) return separatedAmount()
if (_isRetired) return retiredAmount()
return normalPayAmount()
}
5. 以HashMap取代條件表達式
// bad
let getSpeed = type => {
switch (type) {
case SPEED_TYPE.AIR:
return getAirSpeed()
case SPEED_TYPE.WATER:
return getWaterSpeed()
...
}
}
// good
let speedMap = {
[SPEED_TYPE.AIR]: getAirSpeed,
[SPEED_TYPE.WATER]: getWaterSpeed
}
let getSpeed = type => speedMap[type] && speedMap[type]()
其他
實踐以上列舉的重構方法,能解決項目中大部分的壞代碼,但還有許多重構方法,能讓你的代碼變得幹凈整潔易於閱讀。
- 清晰的項目目錄結構
- ES6+語法糖
- [ ] arrow function
- [ ] rest
- [ ] 函數默認參數
- [ ] async/await
-
[ ] let/const 代替var
- 常用全部使用const,並字母全部為大寫
- 使用合適的函數名或變量名代替註釋
- 善於利用js中的&& 與 ||
- 避免‘否定情況’的判斷
- 盡量不寫全局函數與變量
- 采用函數式編程,ES6 Array支持的很好
- 移除重復的代碼
- 移除註釋的代碼
重構你的 javascript 代碼