前端代碼優(yōu)化與重構(gòu)

提煉函數(shù)

這個方法是我們最經(jīng)常做的優(yōu)化,我們希望在編程過程中,函數(shù)都有良好的命名,而且在函數(shù)的內(nèi)部包含清晰的邏輯阔馋,我們在日常編程的過程中,我們往往會向一個函數(shù)中塞入大量的代碼娇掏,使其違反了單一變量的原則呕寝。我們不得不在函數(shù)內(nèi)部加入若干的注釋,讓這個函數(shù)顯得容易讀懂一些驹碍,這個時候壁涎,我們就需要對代碼進(jìn)行簡化。我們的做法是:將一些代碼獨立出志秃,放入到另外一個單獨的函數(shù)中怔球。這樣做有如下幾個優(yōu)點:

  • 避免出現(xiàn)超大的函數(shù)
  • 獨立出來的代碼方便進(jìn)行代碼的復(fù)用
  • 獨立出來的函數(shù)更加容易被覆寫
  • 獨立出來的函數(shù)如果擁有一個良好的命名,它本身就起到了一個注釋的作用浮还。

我們用一段代碼來舉個栗子竟坛,我們只一個負(fù)責(zé)獲取用戶信息的函數(shù)里面,我們還需要打印用戶信息相關(guān)的log钧舌。我們將打印的語句封裝到一個獨立的函數(shù)里面:

//優(yōu)化前
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);
  });
};

//優(yōu)化后
var getUserInfo = function(){
   ajax('http://XXX.com/userInfo', function( data){
    printDetail(data);
  });
};

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

合并重復(fù)的條件判斷

如果我們在函數(shù)的內(nèi)部有一些條件分支語句担汤,然后在這些條件分支語句中散布了一些重復(fù)的代碼,那么我們就有必要做一些合并的工作洼冻、現(xiàn)在給出一個應(yīng)用的場景:假設(shè)我們有一個分頁的函數(shù)paging崭歧,這個函數(shù)接受一個參數(shù)currPagecurrPage表示要跳轉(zhuǎn)的頁碼撞牢,在跳轉(zhuǎn)之前要防止currPage過大或是過小率碾,我們要進(jìn)行手動的修正∥荼耄看一段偽代碼:

//優(yōu)化前
var paging = function(){
  if(currPage <= 0){
    currPage = 0;
    jump(currPage);
  }else if(currPage >= totalPage){
    currPage = totalpage;
    jump(currPage);
  }else{
    jump(currPage);
  }
}

上面的代碼我們可以看到所宰,負(fù)責(zé)跳轉(zhuǎn)的代碼jump(currPage)在每一個條件分支中都出現(xiàn)了,所以完全可以把這部分的代碼獨立出來

//優(yōu)化后
var paging = function (currPage){
  if(currPage <= 0){
    currPage = 0;
  }else if (currPage > = totalPage){
    currPage = totalPage;
  }
  jump(currPage);
}

將條件分支語句提煉成函數(shù)

我們在編程過程中畜挥,可能看到別人的代碼有大連的if-else語句仔粥,導(dǎo)致最后代碼的可讀性很差。舉一個生活中的例子:現(xiàn)在有一個計算商品的函數(shù),計算的規(guī)則是躯泰,如果當(dāng)前季節(jié)處于夏季谭羔,那么全部的商品將以8折出售,代碼如下

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

我們要判斷的表達(dá)的意思是很簡單的斟冕,就是判斷當(dāng)前是否為夏季口糕,但是我們在if的語句中缅阳,很難得到代碼想要表達(dá)的意思磕蛇。這個時候我們可以將這段代碼提煉成一個單獨的函數(shù),就可以更加準(zhǔn)確地表達(dá)代碼的意思十办,函數(shù)本身的函數(shù)名也可以起到注釋的作用秀撇。

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

合理的使用循環(huán)

在函數(shù)體的內(nèi)部,會有很多的重復(fù)性的工作向族,那么合理的使用循環(huán)呵燕,就是我們需要考慮的問題,使用循環(huán)可以減少代碼量件相。加入我們創(chuàng)建XHR對象的代碼再扭,在這里就不考慮瀏覽器的兼容性了。

var createXHR = function(){
  var xhr;
  try{
    xhr = new ActiveXObject('MSXML2.XMLHTTP.6.0');
  }cache(e){
    try{
         xhr = new ActiveXObject('MSXML2.XMLHTTP.3.0');
     }cache(e){
       xhr = new ActiveXObject('MSXML2.XMLHTTP');
     }
  }
  return xhr;
}
var xhr = createXHR ();

現(xiàn)在我們對上面的代碼進(jìn)行優(yōu)化夜矗,巧妙的使用循環(huán)泛范,達(dá)到和上面代碼一樣的效果:

var createXHR = function(){
  var versions = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
  for(let i = 0,version; version = versions[i++]){
    try{
      return new ActiveXObject(version);
    }cache(e){
    }
  }
};
var xhr = createXHR ();

提前讓函數(shù)退出代替嵌套條件分支

我們的編程習(xí)慣讓我們有這樣的觀念:“每一個函數(shù)只能有一個出口和入口”∥伤海現(xiàn)代的編程語言都會限制函數(shù)只有一個入口罢荡,但是對于函數(shù)只有一個出口都是有不同的看法。

var del = function(obj){
  var ret;
  if(!obj.isReadyOnly){//文件是只讀模式
    if(obj.isFloder){//是文件夾
      ret = deleteFloder(obj);
    }else if(obj.isFile){//是文件形式
      ret = deleteFile(obj)
    }
  }
  return ret;
};

嵌套的條件分支語句絕對是代碼維護(hù)者的噩夢对扶,因為邏輯看上去十分的混亂区赵,理解上十分的困難,有的時候外層的if分支在左括號和有括號相隔很遠(yuǎn)浪南,理解上就更加復(fù)雜了額笼才,我們之前在編程的時候,一直堅信络凿,一個函數(shù)只有一個出口骡送,實際上程序?qū)κO虏糠值倪壿嫴⒉魂P(guān)注,所以這個時候可以立即退出喷众,不會引導(dǎo)程序員去看一些無用的else的語句各谚。

var del = function(obj){
  var ret;
  if(!obj.isReadyOnly){//文件是只讀模式
    return;
   }
  if(obj.isFloder){//是文件夾
    return  deleteFloder(obj);
  }
  if(obj.isFile){//是文件形式
   return deleteFile(obj)
   }
};

傳遞參數(shù)對象代替過長的參數(shù)列表

有的時候,一個函數(shù)可以接受多個參數(shù)到千,而且參數(shù)的數(shù)量越多昌渤,函數(shù)的功能越難理解。因為使用這個函數(shù)的用戶必須知道各個參數(shù)的作用是什么憔四,使用的時候膀息,還要小心謹(jǐn)慎般眉,避免多傳或是少傳參數(shù),造成錯誤潜支,而且當(dāng)我們想要添加參數(shù)的時候甸赃,設(shè)計到很多的代碼的修改。

var setUserInfo = function(id,name, address, sex, mobile,qq){
  console.log('id:'+id);
  console.log('name:'+name);
  console.log('address:'+address);
  console.log('sex:'+sex);
  console.log('mobile:'+mobile);
  console.log('qq:'+qq);
}
setUserInfo (1212, 'kim','shanghai','female','123456788912',12345678978)

我們可以將參數(shù)放入到一個對象里面冗酿,然后在將對象傳入到函數(shù)中埠对,而且不用再傳參的時候關(guān)心參數(shù)的順序和數(shù)量,只要保證參數(shù)的key值不變就可以了裁替。

var setUserInfo = function(obj){
  console.log('id:'+id);
  console.log('name:'+name);
  console.log('address:'+address);
  console.log('sex:'+sex);
  console.log('mobile:'+mobile);
  console.log('qq:'+qq);
}

setUserInfo ({
  id:1212,
  name:'kim',
  address:'shanghai',
  sex:'female',
  mobile:'123456788912',
  qq:12345678978
})

盡減少參數(shù)的數(shù)量數(shù)量

如果我們向一個函數(shù)中傳入很多的參數(shù)项玛,那么我們使用的時候,要先搞懂參數(shù)的意義弱判,這樣很浪費時間襟沮。但是在實際的開發(fā)過程中,向函數(shù)傳入?yún)?shù)是不可避免的昌腰,我們假設(shè)一下下面的應(yīng)用場景:有一個畫圖的函數(shù)draw开伏,他現(xiàn)在只可以繪制長方形,接受了3個參數(shù)遭商。分別是長寬和面積固灵,但是我們知道,面積是可以通過長和寬計算出來的株婴。

var draw  = function(width怎虫, height,width)

所以我們對上面的代碼進(jìn)行優(yōu)化困介,將square參數(shù)從函數(shù)中去掉

var draw  = function(width大审, height){
  var square = width * height;
}

假設(shè)日后這個draw函數(shù)支持繪制原型,我們就需要把長和寬的參數(shù)換成半徑radius座哩,但是圖形的面積還是不應(yīng)該由客戶端進(jìn)行傳入徒扶,而是應(yīng)該在draw函數(shù)的內(nèi)部,由一定的規(guī)則進(jìn)行計算根穷。這個時候就可以使用策略模式姜骡,讓draw函數(shù)支持說中圖形的繪制。

慎用三目運算符

有一些程序員喜歡使用三目運算符來代替if-else的語句屿良,因為代碼量少圈澈,運算性能高。但是三目運算符的運算性能并不比if-else高很多尘惧。而且在負(fù)責(zé)的邏輯中使用三目運算符會降低代碼的可讀性和可維護(hù)性康栈。而且讓js文件加載的速度加快的方法有很多。比如說壓縮、緩存等等啥么,但是僅僅把關(guān)注點放在使用三目運算符的數(shù)目上登舞,無異于將一個300斤超重的胖子的超重原因歸結(jié)到了頭皮屑上面。
什么時候使用三目運算符:當(dāng)條件分支的邏輯十分的簡單清楚悬荣。

var global = typeof window !== 'undefined'? window:this;

但是如果我們的條件十分的復(fù)雜菠秒,我們還是按部就班的寫if語句比較好

if(!aup || bup){
  return a === doc ? -1:
    b=== doc ? 1:
    aup ? -1:
    bup ? 1:
    sortInput ?
    (indexOf.call (sortInput,a) - indexOf.call(sortInput,b)):
    0
}

合理的使用鏈?zhǔn)秸{(diào)用

經(jīng)常使用jquery的程序員比較習(xí)慣使用鏈?zhǔn)秸{(diào)用的寫法,在JavaScript中氯迂,可以很容易的實現(xiàn)鏈?zhǔn)秸{(diào)用践叠,即讓方法調(diào)用結(jié)束后返回對象自身。

var User = function (){
  this.id = null;
  this.name = null;
};
User.prototype.setId =  function (id){
  this.id = id;
  return this;
}
User.prototype.setName =  function (name){
  this.name= name;
  return this;
}
console.log(new User().setId(1212).setName('kim'));

//寫法二
var User = {
  id : null,
  name: null,
  setId: function(id){
    this.id = id;
    return this;
  }
  setId: function(name){
    this.name = name;
    return this;
  }
};
console.log(User.setId(1212).setName('kim'));

通常來說囚戚,臉是調(diào)用的方式并不會造成閱讀理解時候的困難酵熙,也可以減少一些中間變量,但是節(jié)省下來的字節(jié)幾乎可以忽略布局驰坊。鏈?zhǔn)秸{(diào)用帶來的壞處就是調(diào)試的時候十分的不方便,只要中間一節(jié)出現(xiàn)了錯誤哮独,必須將整條鏈拆開拳芙,再添加斷點,才可以定位錯誤出現(xiàn)的位置皮璧。

用return退出多重循環(huán)

假設(shè)函數(shù)體內(nèi)有一個兩重的循環(huán)語句舟扎,我們需要內(nèi)層循環(huán)中判斷,當(dāng)?shù)竭_(dá)某個臨界條件時退出外層的循環(huán)悴务。我們大多數(shù)時候會引入一個控制標(biāo)記變量:

var func  = function(){
  var flag = false;
  for(let i = 0; i< 10 ; i++){
    for(let j = 0; j < 10; j++){
      if(i *j > 30){
        flag = true;
        break;
      }
    }
    if(flag === true){
      break;
    }
  }
};

第二種寫法是設(shè)置循環(huán)標(biāo)記:

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

這兩種做法都沒有錯睹限,但是還有更加簡單的做法,就是在終止循環(huán)的時候讯檐。直接的退出整個方法:

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

當(dāng)然直接這么寫又會帶來一個新的問題羡疗,就是如果在循環(huán)后還有一些將要被執(zhí)行的代碼,直接退出整個方法别洪,這些方法就不會有被執(zhí)行的機會了叨恨,舉個栗子:

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

為了我們解決這個問題,我們將循環(huán)后的戴拿直接放在return的后面挖垛,如果代碼的比較多痒钝,就直接將其提煉成一個函數(shù)。

var print = function(i){
  console.log(i)
} ;
var func = function(){
  for(let i = 0; i <10;i++){
    for (let j = 0;j <10; j++){
      if(i *j >30){
        return print (i);
      }
    }
  }
};
func();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痢毒,一起剝皮案震驚了整個濱河市送矩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哪替,老刑警劉巖栋荸,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡蒸其,警方通過查閱死者的電腦和手機敏释,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摸袁,“玉大人钥顽,你說我怎么就攤上這事】恐” “怎么了蜂大?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蝶怔。 經(jīng)常有香客問我奶浦,道長,這世上最難降的妖魔是什么踢星? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任澳叉,我火速辦了婚禮,結(jié)果婚禮上沐悦,老公的妹妹穿的比我還像新娘成洗。我一直安慰自己,他們只是感情好藏否,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布瓶殃。 她就那樣靜靜地躺著,像睡著了一般副签。 火紅的嫁衣襯著肌膚如雪遥椿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天淆储,我揣著相機與錄音冠场,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蛔屹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼青团,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了咖楣?” 一聲冷哼從身側(cè)響起督笆,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诱贿,沒想到半個月后娃肿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咕缎,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年料扰,在試婚紗的時候發(fā)現(xiàn)自己被綠了凭豪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡晒杈,死狀恐怖嫂伞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拯钻,我是刑警寧澤帖努,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站粪般,受9級特大地震影響拼余,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜亩歹,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一匙监、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捆憎,春花似錦舅柜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽变抽。三九已至础拨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绍载,已是汗流浹背诡宗。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留击儡,地道東北人塔沃。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像阳谍,于是被迫代替她去往敵國和親蛀柴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line)矫夯,也就是一...
    悟名先生閱讀 4,148評論 0 13
  • 截圖 打開模擬器 選擇需要截屏的頁面 按Command+S鍵進(jìn)行截屏鸽疾,截屏文件一般存儲在當(dāng)前桌面 錄屏 打開模擬器...
    ManThirty閱讀 1,579評論 0 0
  • chaocre閱讀 163評論 0 0
  • 春天的陽光要把我曬裂 讓我心中的種子,在縫隙中生長 你遠(yuǎn)遠(yuǎn)地看著我 在夜深人靜的時候借助風(fēng) 送我一點滋潤的雨露 因...
    泰安左眼皮跳跳閱讀 212評論 0 8
  • 你說人家寫出來都是高山和流水 而我只有下三路和姑娘的乳房 你說在這樣的夜里 人家喜歡端著茶思考人生 而我永遠(yuǎn)都只有...
    娃哈哈烏拉拉閱讀 156評論 0 1