JavaScript 風格指南(筆記)

變量

  • 使用有意義、可讀性好的變量
  • 使用 ES6 的 const 聲明常量
  • 對功能相似的變量名採用統一的命名風格
  • 使用易於檢索名稱git

    舉例
    // 反例
    for (var i = 0; i < 525600; i++) {
      runCronJob();
    }
    
    // 正例
    var MINUTES_IN_A_YEAR = 525600;
    for (var i = 0; i < MINUTES_IN_A_YEAR; i++) {
      runCronJob();
    }
  • 使用說明變量(即有意義的變量名)
  • 顯式優於隱式(變量名儘可能簡潔明瞭)
  • 避免重複的描述
  • 避免無心義的條件判斷github

    舉例
    var currentPage='';
    var pageNumInfo = JSON.parse(localStorage.getItem('pageNumInfo'));
    if (pageNumInfo) {
        currentPage = parseInt(pageNumInfo[0].pageNum);
    } else {
        currentPage = 1;
    }
    // 以上代碼片斷可用如下代碼取代
    var pageNumInfo = JSON.parse(localStorage.getItem('pageNumInfo')); 
    var currentPage = parseInt(pageNumInfo[0].pageNum) || 1;

函數

  • 函數參數編程

    函數參數理想狀況下應該不超過 2 個。當確實須要多個參數時,大多狀況下能夠考慮將這些參數封裝成一個對象。
  • 保證函數功能的單一性promise

    功能不單一的函數將致使難以重構、測試和理解。功能單一的函數易於重構,並使代碼更加乾淨。
  • 提升函數名的可讀性(函數名應明確代表其功能)
  • 函數應該只作一層抽象服務器

    當函數須要的抽象多於一層時一般意味着函數功能過於複雜,需將其進行分解以提升其可重用性和可測試性。
  • 避免在一個函數中寫重複的代碼
  • 採用默認參數精簡代碼
  • 使用 Object.assign() 設置默認對象
  • 不要使用標記(Flag)做爲函數參數(會破壞函數功能的單一性)
  • 避免反作用數據結構

    函數反作用:當函數產生了除了「接受一個值並返回一個結果」以外的行爲時,稱該函數產生了反作用。好比寫文件、修改全局變量等。
    程序在某些狀況下確實須要反作用這一行爲,如先前例子中的寫文件。這時應該將這些功能集中在一塊兒,不要用多個函數/類修改某個文件。用且只用一個 service 完成這一需求。
  • 不要寫全局函數
  • 採用函數式編程
  • 封裝判斷條件
  • 避免「否認條件」的判斷
  • 避免條件判斷閉包

    許多狀況下經過使用多態(polymorphism)能夠達到一樣的目的。
    // 反例
    class Airplane {
      //...
      getCruisingAltitude() {
        switch (this.type) {
          case '777':
            return getMaxAltitude() - getPassengerCount();
          case 'Air Force One':
            return getMaxAltitude();
          case 'Cessna':
            return getMaxAltitude() - getFuelExpenditure();
        }
      }
    }
    
    // 正例
    class Airplane {
      //...
    }
    
    class Boeing777 extends Airplane {
      //...
      getCruisingAltitude() {
        return getMaxAltitude() - getPassengerCount();
      }
    }
    
    class AirForceOne extends Airplane {
      //...
      getCruisingAltitude() {
        return getMaxAltitude();
      }
    }
    
    class Cessna extends Airplane {
      //...
      getCruisingAltitude() {
        return getMaxAltitude() - getFuelExpenditure();
      }
    }
  • 避免類型判斷
  • 避免過分優化
  • 無效代碼及時刪除

對象和數據結構

  • 使用 getters 和 setters併發

    使用 getters 和 setters 獲取對象的數據遠比直接使用點操做符具備優點,爲何呢??
    一、當須要對獲取的對象屬性執行額外操做時。
    二、執行 set 時能夠增長規則對要變量的合法性進行判斷。
    三、封裝了內部邏輯。
    四、在存取時能夠方便的增長日誌和錯誤處理。
    五、繼承該類時能夠重載默認行爲。
    六、從服務器獲取數據時能夠進行懶加載。
  • 讓對象擁有私有成員。(能夠經過閉包實現)

  • 列表項目
  • 單一職責原則(SRP)
  • 開閉原則(OCP)async

    代碼實體(類,模塊,函數等)應該易於擴展,難於修改。
    即代碼模塊的功能應該要方便用戶拓展而不是修改源碼
  • 利斯科夫替代原則(LSP)函數式編程

    子類對象應該可以替換其超類(父類)對象被使用。
  • 接口隔離原則(ISP)

    客戶端不該該依賴它不須要的接口,一個類對另外一個類的依賴應該創建在最小的接口上。
  • 依賴反轉原則(DIP)

    該原則有兩個核心點:
    一、高層模塊不該該依賴於低層模塊。他們都應該依賴於抽象接口。
    二、抽象接口應該脫離具體實現,具體實現應該依賴於抽象接口。
  • 使用 ES6 的 classes 而不是 ES5 的 Function

    典型的 ES5 的類(function)在繼承、構造和方法定義方面可讀性較差。
    當須要繼承時,優先選用 classes。
    可是,當在須要更大更復雜的對象時,最好優先選擇更小的 function 而非 classes。
  • 使用方法鏈
  • 優先使用組合模式而非繼承

測試

  • 單元測試,單一的測試每一個概念

併發

  • 用 Promise 替代回調(支持 ES6 的狀況,優先使用)
  • async 和 await(支持 ES7 的狀況,優先使用)

錯誤處理

  • try/catch 捕獲異常
  • 不要忽略被拒絕的 promises

格式化

  • 大小寫一致
  • 調用函數的函數和被調函數應放在較近的位置

    當函數間存在相互調用的狀況時,應將二者置於較近的位置。理想狀況下,應將調用其餘函數的函數寫在被調用函數的上方。

註釋

  • 只對存在必定業務邏輯複雜性的代碼進行註釋。註釋並非必須的,好的代碼是可以讓人一目瞭然,不用過多無謂的註釋。
  • 被註釋掉的代碼及時刪除
  • 不須要版本更新類型註釋。須要時可使用 git log 獲取歷史版本。
  • 避免位置標記
  • 避免在源文件中寫入法律評論

參考

相關文章
相關標籤/搜索