重構代碼的tricks

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

封裝功能塊代碼

咱們一般在寫代碼的時候,一開始,並不須要考慮太多。在後期能夠進行修改和提煉。 好比,我有個業務需求,是建立一個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的狀態.咱們能夠對其進行封裝。app

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";
}

提取公因式

這裏主要針對於,屢次重複調用同一個封裝代碼塊函數。ide

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就是.this

不要過分嵌套

這裏想說的就兩點,一是,儘量不使用分支,二是,若是嵌套分支,儘可能改成不嵌套。 不使用分支的狀況上面已經說了,若是使用分支,那麼請不要嵌套,或者說不要過分嵌套。由於一個分支已經很難閱讀了,md,你再加個嵌套,你還讓不讓人讀了。 而解決過分嵌套的方法真的是千千萬萬,我這裏就介紹一個比較簡單的。使用return 提前退出嵌套。prototype

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();

這樣不只能夠實現對象的細粒度,並且也知足單一職責原則。
一樣,我要說的是,覺得的使用鏈式的時候,記住,使用一個功能塊鏈式調用必定要分行,否則,調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();  //表這樣作

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

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

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

相關文章
相關標籤/搜索