almost 5 years ago

閱讀 code 的時間會比 撰寫 的時間來得多,因此寫出容易維護的 code 便顯得相當重要。
容易維護的 code 具備以下條件:

  • 可讀性
  • 一致性(像同一個人寫的)
  • 可預期的
  • 文件化

少用全域變數(global variable)

  • 變數的 scope 在 function 內,即 local variable
  • 定義在 function 外或未經宣告直接使用(不論 function 內外)則為 global
  • JavaScript 執行環境皆有 global object,在 function 外可用 this 進行存取;在 browser 中,window 為 global object 的一個 property,指向 global object 本身,因此也可用 window 存取 global variable
    gvar = "test"; // antipattern
    console.log(gvar); // "test"
    console.log(window.gvar); // "test"
    console.log(window["gvar"]); // "test"
    console.log(this.gvar); // "test"
    
    // 如果在不同執行環境中,window 未必可用,若不寫死可用以下方法
    var global = (function () {
        return this;
    }());
    
  • 使用 global variable 可能發生命名衝突(例如有多個 libraries 或多段不同人寫的 code 時),應盡可能少用
  • chain assignment 也會建立 global variable
    function foo() {
        var a = b = 0; // a: local; b: global
        var c, d;
        c = d = 0; // c: local; d: local
    }
    
  • 隱含的 global variable(即未經 var 宣告就直接使用的)可以用 delete 刪除;因為該變數嚴格來說其實是 global object 的 property 而非變數,delete 可刪除 object 的 property 而不能刪除變數

使用單一 var

  • hoisting 行為:在任何位置以 var 宣告變數,其行為與「在頂端宣告」相同
    bar = "global"; // global variable
    function foo() {
        console.log(bar); // "undefined"
        var bar = "local";
        console.log(bar); // "local"
    }
    foo();
    // 上例相當於以下行為
    bar = "global"; // global variable
    function foo() {
        var bar; // same as: var bar = undefined;
        console.log(bar); // "undefined"
        bar = "local";
        console.log(bar); // "local"
    }
    foo();
    
  • 在 function 開頭使用單一 var 敘述,優點:
    • 查閱使用變數時只需找一個地方
    • 避免 hoisting 行為造成的邏輯錯誤
    • 減少「造成隱含的全域變數」發生
    • 使 code 字數更精簡
      function foo() {
          var a = 0,
              b = 1,
              sum = a + b,
              myobj = {},
              i,
              j,
              result = document.getElementById("result"),
              resultStyle = result.style;
      }
      

預先計算 iteration 次數

  • 使用 for loop 時預先計算次數,以避免每次皆計算而影響效能(尤其針對 HTMLCollection object 時影響更大)
    for (var i = 0, max = myarray.length; i < max; i++) {
        // ...
    }
    
  • 效能更佳的 loop(只使用一個變數且只判斷零與非零)
    // for-loop
    var i, myarray = [];
    for (i = myarray.length; i--;) {
        // ...
    }
    // while-loop
    var myarray = [],
        i = myarray.length;
    while (i--) {
        // ...
    }
    // 註:JSLint 看到 ++ 或 -- 會抱怨
    
  • for-in loop 不保證列出的順序,建議將 for 用於重複 array,將 for-in 用於重複 object
  • 使用 for-in 時應加上 hasOwnProperty() 檢查該 property 是否來自 prototype,因為擴充 prototype 的行為是 live,所有已存在的 object 將自動能存取新加入的 property
    var dog = {
        eye: 2,
        head: 1,
        leg: 4
    }
    // 在某處將一個新 method 加入到所有 object 中
    if (typeof Object.prototype.clone === "undefined") {
        Object.prototype.clone = function () {};
    }
    // 1. for-in loop
    for (var i in dog) {
        // 兩種用法皆可
        // if (Object.prototype.hasOwnProperty.call(dog, i)) {
        if (dog.hasOwnProperty(i)) {
            console.log(i, ":", dog[i]);
        }
    }
    /*
    console 中的結果:
    eye : 2
    head : 1
    leg : 4
    */
    // 2. antipattern (no hasOwnProperty())
    for (var i in dog) {
        console.log(i, ":", dog[i]);
    }
    /*
    console 中的結果:
    eye : 2
    head : 1
    leg : 4
    clone : function () {}
    */
    

Coding Conventions

  • 縮排很重要
  • 永遠都應加上大括號,即使只是單行敘述
  • 左大括號置於同一行
  • 適當地加入空格
  • 以空白行分隔不同段落

Naming Conventions

  • 將 constructor function 首字使用大寫,一般 function 則用小寫
  • 駝峰式命名法:僅每個字的第一個字母使用大寫,其餘皆小寫
  • 常數採用全大寫命名;全域變數也可考慮使用全大寫字母
  • 在變數前或後加底線來表示 private member,如 getElements_()(JSLint 會對底線前綴警告)

其他

  • 最好不要擴充內建型別(Object(), Array(), Function(), etc.)的 prototype
  • switch 中,case 不應縮排,最後務必以 break; 結束每個 case,務必以 default: 結束 switch
  • 避免造成隱含的型別轉換,應使用 ===!== 同時比較型別與值 (reference)
  • 避免使用 eval(),若非用不可時可改用 new Function() 或 immediate function
  • 為避免回傳 NaN,建議使用 parseInt() 將 string 轉成 number,且第二個參數(進位制的基數)不應省略
    var month = "03";
    month = parseInt(month, 10); // 10進位
    
  • 生成 API 文件的工具:
← JavaScript Patterns 閱讀筆記 (1) Introduction JavaScript Patterns 閱讀筆記 (3) Literals and Constructors →
 
comments powered by Disqus