重構代碼的tricks

pkcv1724 8年前發布 | 9K 次閱讀 設計模式 JavaScript開發

來自: http://segmentfault.com/a/1190000004360784

js的設計模式是針對于整體代碼的設計是否合理,給出了一些具體的解決辦法。 而重構代碼就是依賴于設計模式而實現的一個必要手段,可以說設計模式就是重構代碼的目標,但他的手段卻不僅僅只有設計模式這些大而全的,同樣存在小而精,我們隨處可以使用的。

封裝功能塊代碼

我們通常在寫代碼的時候,一開始,并不需要考慮太多。在后期可以進行修改和提煉。 比如,我有個業務需求,是創建一個div并且渲染數據到頁面上,并且根據data的不同,改變div的狀態.

function(data){
    var div = document.createElement("div"),
    div.innerHTML = data.name;
    document.body.append(div);
    if(data.isShow){
        div.style.display = "block";
    }else{
        div.style.display = "none";
    }
}

但事實上,這個函數里面還有一個代碼塊,就是根據data.isShow改變div的狀態.我們可以對其進行封裝。

function(data){
    var div = document.createElement("div"),
    div.innerHTML = data.name;
    document.body.append(div);
    changeState(data.isShow,div);
}
function changeState(flag,div){
    div.style.display = flag?"block":"none";
}

提取公因式

這里主要針對于,多次重復調用同一個封裝代碼塊函數。

function(flag){
    if(flag==="left"){
        move("right");
    }else if(flag==="right"){
        move("left");
    }else if(flag==="top"){
        move("bottom");
    }else if(flag==="bottom"){
        move("top");
    }
}

根據flag向反方向移動,可以看出,里面都有用到了move()這個方法,要知道,分支語句是最不利于程序閱讀的,而且我們要盡可能的減少和簡化分支語句里面的程序量,讓閱讀者耗費在分支語句上的時間降到最少。上面代碼可以這樣寫。

function(flag){
    var dir;
    if(flag==="left"){
        dir = "right";
    }else if(flag==="right"){
        dir = "left";
    }else if(flag==="top"){
        dir = "bottom";
    }else if(flag==="bottom"){
        dir = "top";
    }
    move(dir);
}

恩,當然,這樣寫也是違反人性的。我們可以使用命令模式進行重構。這就涉及到另外一個tip.

將分支轉化為函數

上面代碼里面的分支完全可以使用函數來進行代替。

function(flag){
    command.flag;
}
var command = (function(){
    var left = function(){
        move("right");
    }
    var right = function(){
        move("left");
    }
    var top = function(){
        move("bottom");
    }
    var bottom = function(){
        move("top");
    }
    return {
        left,right,top,bottom
    }
})();

這樣,雖然增加了一個對象,但是代碼確實清晰可見的。 這就是通過命令模式,來重構代碼,完成性能和閱讀的優化。但有時候,使用分支,會比這樣更簡潔,那當然可以使用分支啦。 而使用分支還要主意一個tip就是.

不要過度嵌套

這里想說的就兩點,一是,盡可能不使用分支,二是,如果嵌套分支,盡量改為不嵌套。 不使用分支的情況上面已經說了,如果使用分支,那么請不要嵌套,或者說不要過度嵌套。因為一個分支已經很難閱讀了,md,你再加個嵌套,你還讓不讓人讀了。 而解決過度嵌套的方法真的是千千萬萬,我這里就介紹一個比較簡單的。使用return 提早退出嵌套。

function move(obj){
    if(obj.isShow){
        if(obj.isTop){
            if(obj.isLeft){
                return move("TopLeft");
            }
        }else{
            return false;
        }
    }else {
        return false;
    }
}

這,看著爽不爽。 如果,我遇見這樣的代碼,我第一反應就是,要!死!啦!. 所以,為了讓你的程序人性化,我們可以使用return 語句進行改寫。 我們可以對條件判斷的邏輯進行分析,可以看出,里面如果條件不滿足都是返回false,那么我們可以將false的情況提取出來。

function move(obj){
    if(!obj.isShow){
        return false;
    }
    if(!obj.isTop){
        return false;
    }
    if(!obj.isLeft){
        return false;
    }
    return move("TopLeft");
}

這是這個feel。當然,追求極致的話,我們可以看出return false,是完全一致的,當然可以將條件合并.

function move(obj){
    if(!obj.isShow||!obj.isTop||!obj.isLeft){
        return false;
    }
    return move("TopLeft");
}

其實如果你數學學得好的話(我還行吧,嘿~嘿~嘿~)。 這樣提取條件的事是輕而易舉的,可以看出,上面那段古老的代碼完全可以變為現在這個樣式,而且讀起來,真的不是一個檔次的。

減少參數數量

減少參數數量的方法,當然永遠不會===1, 因為每個人站的角度不同,得到的答案當然也不一樣。所以這里只介紹兩種比較通用的。

  1. 使用對象來代替參數列表。

  2. 將需要額外計算的參數忽略。

使用對象代替參數

這個最突出的特點就是在寫模板的時候。

function templ(name,age,gender){
    return `my name is ${name}. and I'm ${age} years old. yeah! I am a ${gender}`;
}

有一個模板,上面需求的參數有三個,但是,事實上,這個是完全不靠譜的。 因為一個人不僅僅只有name,age,gender 肯定還有別的參數,這樣,造成的后果就是,你一直在維護模板的同時,還需要維護參數列表。而且,還要維護,傳入參數的順序的正確性。所以這里強烈推薦使用對象來代替多參數。

function templ(person){
    return `my name is ${person.name}. and I'm ${person.age} years old. yeah! I am a ${person.gender}`;
}

現在這個模板函數與外界的耦合性已經降低了不少。而且非常易于維護,就算外面你的person對象有多余的參數,也不會妨礙我使用我需要的數據。

忽略額外計算的參數

這種情況主要是在做UI的時候可能會遇到,即,想繪制一個數據table的時候,需要將一個數據矩形的高,寬以及面積傳入一個函數,進行繪制。

function column(width,height,square){
    console.log("矩形的寬度為"+width);
    console.log("矩形的高度為"+height);
    console.log("矩形的面積為"+square);
}

而,這樣做是完全沒有必要的,因為函數參數越少,給人的感覺當然越好。我們可以修改為這樣.

function column(width,height){
    var square = width*height;
    console.log("矩形的寬度為"+width);
    console.log("矩形的高度為"+height);
    console.log("矩形的面積為"+square);
}

而且在插件設計中,也應該準遵守這個原則,函數的參數應該在能力范圍內,把它降至最少。

鏈式調用

這個應該算是比較高級的用法。使用過jQuery的同學應該印象最深刻。 即,我們可以這樣來使用一個功能.

$(".myClass").addClass("show").attr('data-name').css("display","none");

而這樣實現其實并不難,只要在每個方法的后面返回該對象就可以實現這個技能。我們來模仿一下。

var Div = function(){

} Div.prototype.createElement = function(){ console.log("創建一個Div"); return this; } Div.prototype.showDiv = function(){ console.log("顯示Div"); return this; } var div = new Div(); div.createElement().showDiv();</pre>

這樣不僅可以實現對象的細粒度,而且也滿足單一職責原則。同樣,我要說的是,以為的使用鏈式的時候,記住,使用一個功能塊鏈式調用一定要分行,不然,調bug會調哭的。

var Div = function(){

} Div.prototype.createElement = function(){ console.log("創建一個Div"); return this; } Div.prototype.showDiv = function(){ console.log("顯示Div"); return this; } Div.prototype.hideDiv = function(){ console.log("隱藏Div"); return this; } Div.prototype.tagName = function(){ console.log("tagName 是 Div"); return this; } var div = new Div(); div.createElement().showDiv().tagName().hideDiv(); //表這樣做</pre>

上面是個反例,正確的做法,應該分開。

div.createElement()
.showDiv()
.tagName()
.hideDiv();

像這樣調用,萬一出個Bug,你也應該知道這個bug在哪一個函數塊內。大部分重構的小技巧差不多介紹完了(智商有限),如果,大家有什么更好的建議歡迎留言反饋.

</div>

 本文由用戶 pkcv1724 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!