重構你的javascript代碼

重構,對於每一個開發者都相當重要,特別是對於那些須要進階的高級程序員。根據二八理論,20%的重構方法,能解決80%的壞代碼。筆者最近查閱較多js編碼指南以及從新閱讀了《代碼整潔之道》、《重構:改善既有代碼的設計》兩本經典書籍(強烈建議每隔一段時間看,每次都有新體會),整理出如下幾個要點,幫助你們以最小的記憶,重構大部分壞代碼。若是想全面瞭解重構方式,能夠看筆者整理的AI Javascript風格指南javascript

壞代碼判斷

壞代碼對每一個人、每一個項目標準都不同,但如下幾點大機率會是壞代碼,須要使用重構方法進行代碼重構。css

  • 重複代碼
  • 過長函數
  • 過大的類
  • 過長參數列表

重構方法

1. 好的命名

好的命名貫穿整個軟件編碼過程,好命名包括合理使用大小寫定義、縮進等。目前前端工程提供不少lint或format工具,能很方便的幫助工程檢測和自動化,不清楚的同窗能夠看看筆者AI前端工具鏈。無論是變量名、函數名或是類名,一個好的命名會加快自身開發效率以及閱讀代碼效率,畢竟程序讀的次數會比寫的次數多的多。讀github上優秀源碼就知道,有時候只要看函數名就知道做者的意圖。html

// 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]()
複製代碼

其餘

實踐以上列舉的重構方法,能解決項目中大部分的壞代碼,但還有許多重構方法,能讓你的代碼變得乾淨整潔易於閱讀。java

  • 清晰的項目目錄結構
  • ES6+語法糖
    • arrow function
    • rest
    • 函數默認參數
    • async/await
    • let/const 代替var
    • Array Methods
  • 經常使用所有使用const,並字母所有爲大寫
  • 使用合適的函數名或變量名代替註釋
  • 善於利用js中的&& 與 ||
  • 避免‘否認狀況’的判斷
  • 儘可能不寫全局函數與變量
  • 採用函數式編程,ES6 Array支持的很好
  • 移除重複的代碼
  • 移除註釋的代碼

參考文章

相關文章
相關標籤/搜索