這是《 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個就須要轉化成對象形式。
鏈式調用在調試的時候很是不方便,若是一條調用鏈中有錯誤出現,必需要把這條調用鏈拆開才能定位錯誤出現的地方。
若是該鏈條的結構穩定,後期不易發生修改,使用鏈式調用無可厚非,可是若是該鏈條容易發生變化,致使調試和維護困難,那麼普通調用形式爲佳。
若是一個類的方法足夠複雜和龐大,那麼它徹底有必要做爲一個單獨的類存在。面向對象設計鼓勵將行爲分佈在合理數量的更小對象之中。
在函數有兩重循環語句時,咱們每每須要在內層循環中判斷,當達到臨界條件時退出外層循環,有如下實現方式。
設置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; } } }
設置循環標記
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); } } } };