這是一個持續跟新的文章。
這篇文章會記錄下我對代碼重構的思考和讀書的總結。
1.提煉函數
- 在JavaScript開發中,我們大部分時間都在與函數打交道,所以我們希望這些函數有良好的命名,函數體內包含的邏輯清晰明瞭。
- 如果一個函數過長,不得不加上若干註釋才能讓這個函數顯得易讀一些,那這些函數就很有必要進行重構。
- 如果在函數中有一段代碼可以被獨立出來,那我們最好把這些代碼放進另外一個獨立的函數中,好處有如下幾點。
- 避免出現超大函數。
- 獨立出來的函數有助於代碼複用。
- 獨立出來的函數更容易被覆寫。
- 獨立出來的函數如果有一個良好的命名,它本身就起到了註釋的作用。
var getUserInfo = function () {
ajax('http:// xxx.com/userInfo', function (data) {
console.log('userId:' + data.userId);
console.log('userName:' + data.userName);
console.log('nickName:' + data.nickName);
});
};
改成:
var getUserInfo = function () {
ajax('http:// xxx.com/userInfo', function (data) {
printDetails(data);
});
};
var printDetails = function (data) {
console.log('userId:' + data.userId);
console.log('userName:' + data.userName);
console.log('nickName:' + data.nickName);
}
2.合併重複的條件片段
var paging = function (currPage) {
if(currPage <= 0){
currPage = 0;
jump(currPage);
}else if(currPage >= totalPage){
currPage = totalPage;
jump(currPage);
}else{
jump(currPage);
}
};
可以看到,負責跳轉的代碼jump(currPage)在每個條件分支內都出現了,所以完全可以把這句代碼獨立出來。
var paging = function (currPage) {
if(currPage <= 0){
currPage = 0;
}else if(currPage >= totalPage){
currPage = totalPage;
}
jump(currPage);
};
3.把條件分支語句提煉成函數
var getPrice = function (price) {
var date = new Date();
if(date.getMonth() >= 6 && date.getMonth() <= 9){
return price * 0.8;
}
return price;
}
上面的代碼表達的意圖和代碼自身還存在一些距離,閱讀代碼的人必須要多花一些精力才能明白它傳達的意圖。
其實可以把這句代碼提煉成一個單獨的函數,技能更準確地表達代碼的意思,函數名本身又能起到註釋的作用。
代碼如下
var isSummer = function () {
var date = new Date();
return date.getMonth() >= 6 && date.getMonth() <= 9;
}
var getPrice = function (price) {
if(isSummer()){
return price * 0.8;
}
return price;
};
4.提前讓函數退出代替嵌套條件分支
許多程序員都有這樣一個觀念:“每個函數只能有一個入口和一個出口。”現代編程語言都會限制函數只有一個入口。但關於“函數只有一個出口”,往往會有一些不同的看法。
下面這段僞代碼是遵守“函數只有一個出口”的典型代碼:
var del = function (obj) {
var ret;
if(!obg.isReadOnly) {
if(obj.isFolder) {
ret = deleteFolder(obj);
}else if (obj.isFile){
ret = deleteFile(obj);
}
}
return ret;
}
用《重構》中的話說,嵌套的條件分支往往是由一些深信“每個函數只能有一個出口的”程序員寫出的。
但實際上,如果對函數的剩餘部分不感興趣,那就應該立即退出。
引導閱讀者去看一些沒有用的else片段,只會妨礙他們對程序的理解。
var del = function (obj) {
if(obj.isReadOnly){
return;
}
if(obj.isFolder){
return deleteFolder(obj);
}
if(obj.isFile){
return deleteFile(obj);
}
}