代碼書寫優化(javaScript設計模式與開發實踐--讀書筆記)

這是《 javaScript設計模式與開發實踐 》一書的最後一章"代碼重構"。javascript

如下的一些方法不是必須嚴格遵照的標準,選擇實踐哪些,以及如何實現這都需根據狀況而定(是否是有充足時間)java

提煉函數

若是在函數中有一段代碼能夠獨立出來,那麼最好把這些代碼放進另一個獨立的函數當中去。好處有:ajax

  • 避免出現超大型函數。編程

  • 獨立出來的函數有助於代碼複用。設計模式

  • 獨立出來的函數更加容易被改寫,減小維護成本。瀏覽器

  • 獨立出來的函數若是有一個良好的命名,自己就起到了註釋的做用。編程語言

例如一個獲取用戶信息的函數,咱們還須要打印用戶信息,這種狀況下就能夠獨立出打印信息的代碼。函數

var getUserInfo = function() {
    ajax('http://xxx/userInfo', function(data) {
        console.log('userId: ' + data.userId);
        console.log('userName: ' + data.userName);
        console.log('nickName: ' + data.nickName);
    });
};

改寫:oop

var getUserInfo = function() {
    ajax('http://xxx/userInfo', function(data) {
        printUserInfo(data);
    });
};

var printUserInfo = function(data) {
    console.log('userId: ' + data.userId);
    console.log('userName: ' + data.userName);
    console.log('nickName: ' + data.nickName);
};

合併重複代碼片斷

若是一個函數內有一些條件語句,而條件語句內散佈了一些重複代碼,就有必要進行合併去重工做。設計

例如一個分頁函數paging,函數接受一個currpage表示挑戰頁碼,在跳轉前須要判斷currpage是否在有效的取值範圍。

var paging = function(currpage) {
    if (currpage <= 0) {
        currpage = 0;
        jump(currpage); // 跳轉
    } else if (currpage >= totalPage) { // 總頁數totalPage
        currpage = totalPage;
        jump(currpage); // 跳轉
    } else {
        jump(currpage); // 跳轉
    }
}

負責跳轉的jump(currpage)在每一個條件分支都出現了,因此徹底把這句代碼獨立出來:

var paging = function(currpage) {
    if (currpage <= 0) {
        currpage = 0;
    } else if (currpage >= totalPage) { // 總頁數totalPage
        currpage = totalPage;
    }

    jump(currpage); // 跳轉
}

把條件語句提煉成函數

在程序設計中,複雜的條件語句是致使程序難以閱讀和理解的重要緣由,並且容易增大函數代碼量。例如以一個計算商品價格的getPrice函數,商品計算有個規則,夏天商品以8折出售。

var getPrice = function(price) {
    var date = new Date;
    if (date.getMonth() >= 6 && date.getMonth() <= 9 ) { // 處於夏天
        return price * 0.8
    }
    return price;
}

其中的條件語句if (date.getMonth() >= 6 && date.getMonth() <= 9 )
若是改寫提煉成一個獨立的函數,既能更準確的表達代碼的意思,函數名又能起到註釋做用。

var isSummer = function() {
    var dateMonth = (new Date).getMonth();
    return dateMonth >= 6 && dateMonth <= 9 ;
};

var getPrice = function(price) {
    var date = new Date;
    if ( isSummer() ) { // 處於夏天
        return price * 0.8
    }
    return price;
};

合理使用循環

在函數體內,若是有些代碼是負責一些重複性的工做,那麼合理使用循環不只能夠完成一樣的功能,還可使代碼量更少,有一段建立XHR對象的代碼,爲了簡化代碼,只檢測IE9已下的瀏覽器。

var creatXHR = function() {
    var xhr;
    try{
        xhr = new ActiveXObject('MSXML2.XMLHTTP.6.0');
    } catch(e) {
        try{
            xhr = new ActiveXObject('MSXML2.XMLHTTP.3.0');
        } catch(e) {
            xhr = new ActiveXObject('MSXML2.XMLHTTP');
        }
    }

    return xhr;
};

var xhr = creatXHR();

下面靈活的使用循環,能夠獲得上面代碼同樣的效果:

var creatXHR = function() {
    var versions = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
    for (var i = 0;i < versions.length; i++) {
        try{
            return new ActiveObject( version[i] );
        }catch(e) {

        }
    }
};

var xhr = creatXHR();

提早讓函數退出嵌套條件分支

初學者可能有這樣一個觀念:」每一個函數只能有一個入口和一個出口。」現代編程語言都會限制函數有一個入口。可是關於」函數只有一個出口」,每每有不同的見解。
下面是一個遵照「函數只有一個出口」的代碼。

var del = fucntion(obj) {
    var ret;
    if (!obj.isReadOnly) { // 不爲只讀才能刪除
        if (obj.isFolder) { // 判斷文件夾
            ret = deletFolder(obj);
        } else if (obj.isFile) { // 判斷文件
            ret = deletFile(obj);
        }
    }
    return ret;
}

嵌套的條件分支語句是代碼維護者的噩夢,若是對函數的剩餘部分不感興趣,那就應該當即退出。
咱們能夠挑選一些條件分支,在進入這些條件分支後,就當即讓函數退出。有一個常見的技巧。在面對一個嵌套的if分支時,咱們能夠把外層if表達式進行反轉。例如:

var del = function(obj) {
    if (obj.isReadOnly) { // 反轉表達式
        return;
    }

    if (obj.isFolder) {
        return deletFolder(obj);
    }

    if (obj.isFile) {
        return deletFile(obj);
    }
}

傳遞對象參數代替過長的參數列表

函數可能接受多個參數,參數越多函數就越難理解和使用。

setUserInfo(1111, 'sven', 'hangzhou', 'male', '137*****')

// 可改寫成
setUserInfo({
    id: 1111,
    name: 'sven',
    address: 'hangzhou',
    sex: 'male',
    mobile: '137*****'
})

改寫後能夠再也不關心參數的數量和順序,通常參數控制在4個之內,超過4個就須要轉化成對象形式。

合理使用鏈式調用

鏈式調用在調試的時候很是不方便,若是一條調用鏈中有錯誤出現,必需要把這條調用鏈拆開才能定位錯誤出現的地方。

若是該鏈條的結構穩定,後期不易發生修改,使用鏈式調用無可厚非,可是若是該鏈條容易發生變化,致使調試和維護困難,那麼普通調用形式爲佳。

分解大型類

若是一個類的方法足夠複雜和龐大,那麼它徹底有必要做爲一個單獨的類存在。面向對象設計鼓勵將行爲分佈在合理數量的更小對象之中。

用return退出多重循環

在函數有兩重循環語句時,咱們每每須要在內層循環中判斷,當達到臨界條件時退出外層循環,有如下實現方式。

  1. 設置flag。

var func = function() {
    var flage = false;
    for (var i = 0; i < 10; i++) {
      for (var j = 0; j < 10; j++) {
        if (i * j > 30) {
          flag = true;
          break;
        }
      }
      if (flag === true) {
        break;
      }
    }
}
  1. 設置循環標記

var func = function() {
  outerloop:
  for(var i = 0; i < 10; i++) {
    innerloop:
    for(var j = 0; j < 10; j++) {
      if (i * j >30) {
        break outerloop;
      }
    }
  }
}

這兩種作法都讓人頭暈目眩,更簡單的作法是直接終止整個方法:

var func = function() {
    for (var i = 0; i < 10; i++) {
      for (var j = 0; j < 10; j++) {
        if (i * j > 30) {
          return;
        }
      }
    }
}

return直接退出有一個問題,在循環以後若是還有代碼就沒法執行:

var func = function() {
    for (var i = 0; i < 10; i++) {
      for (var j = 0; j < 10; j++) {
        if (i * j > 30) {
          return;
        }
      }
    }
    console.log(i); // 沒法執行
}

咱們能夠把循環後須要的代碼放到return後面,若是代碼較多,能夠提煉成一個單獨的函數。

var print = function(i) {
  console.log(i);
};
var func = function() {
    for (var i = 0; i < 10; i++) {
      for (var j = 0; j < 10; j++) {
        if (i * j > 30) {
          return print(i);
        }
      }
    }
};
相關文章
相關標籤/搜索