11個 Javascript 小技巧幫你提升程式碼質量,乾貨收藏!
Javascript 常用程式碼優化和重構的方法
簡介
主要介紹以下幾點:
-
提煉函式
-
合併重複的條件片段
-
把條件分支語句提煉成函式
-
合理使用迴圈
-
提前讓函式退出代替巢狀條件分支
-
傳遞物件引數代替過長的引數列表
-
少用三目運算子
-
合理使用鏈式呼叫
-
分解大型類
-
活用位操作符
-
純函式
本文會不斷更新,不足之處歡迎補充。
1. 提煉函式
好處:
-
避免出現超大函式。
-
獨立出來的函式有助於程式碼複用。
-
獨立出來的函式更容易被覆寫。
-
獨立出來的函式如果擁有一個良好的命名,它本身就起到了註釋的作用。
-
語義化將多段分離的邏輯放在不同的函式中實現,可以使程式碼邏輯清晰,清楚的看到每一步在做什麼。
程式碼舉例:
實現獲取資料,然後操作dom顯示資料,最後新增事件
-
函式提煉前
//邏輯都寫在一起,需要將所有邏輯看完才知道這段程式碼是幹嘛的,區域性邏輯無法複用 functionmain(){ $.ajax.get('/getData').then((res)=>{ constul=document.getElementById('ul'); ul.innerHTML=res.list.map(text=>`<liclass="li">${text}</li>`).join('\n'); constlist=document.getElementsByClassName('li'); for(leti=0;i<list.length;i++){ list[i].addEventListener('focus',()=>{ //dosomething }); } }); }
-
函式提煉後
functiongetData(){ return$.ajax.get('/getData').then((res)=>res.data.list); } functionshowList(list){ constul=document.getElementById('ul'); ul.innerHTML=list.map(text=>`<liclass="li">${text}</li>`).join('\n'); } functionaddEvent(){ constlist=document.getElementsByClassName('li'); for(leti=0;i<list.length;i++){ list[i].addEventListener('focus',()=>{ //dosomething }); } } //邏輯清晰,一眼讀懂每一步在做什麼,某些提煉出來的函式還可以被複用 asyncfunctionmain(){ constlist=awaitgetData();//獲取資料 showList(list);//顯示頁面 addEvent();//新增事件 }
2. 合併重複的條件片段
如果一個函式體內有一些條件分支語句,而這些條件分支語句內部散佈了一些重複的程式碼,那麼就有必要進行合併去重工作。
//合併前
functionmain(currPage){
if(currPage<=0){
currPage=0;
jump(currPage);//跳轉
}elseif(currPage>=totalPage){
currPage=totalPage;
jump(currPage);//跳轉
}else{
jump(currPage);//跳轉
}
};
//合併後
functionmain(currPage){
if(currPage<=0){
currPage=0;
}elseif(currPage>=totalPage){
currPage=totalPage;
}
jump(currPage);//把jump函式獨立出來
};
3. 把條件分支語句提煉成函式
複雜的條件分支語句是導致程式難以閱讀和理解的重要原因,而且容易導致一個龐大的函式。有時可以將條件分支語句提煉成語義化的函式,使程式碼更加直觀,邏輯清晰。
//根據不同季節決定打折力度
functiongetPrice(price){
vardate=newDate();
if(date.getMonth()>=6&&date.getMonth()<=9){//夏天
returnprice*0.8;
}
returnprice;
};
//是否是夏天
functionisSummer(){
vardate=newDate();
returndate.getMonth()>=6&&date.getMonth()<=9;
};
//提煉條件後
functiongetPrice(price){
if(isSummer()){
returnprice*0.8;
}
returnprice;
};
4. 合理使用迴圈
如果多段程式碼實際上負責的是一些重複性的工作,那麼可以用迴圈代替,使程式碼量更少。
//判斷是什麼瀏覽器
functiongetBrowser(){
conststr=navigator.userAgent;
if(str.includes('QQBrowser')){
return'qq';
}elseif(str.includes('Chrome')){
return'chrome';
}elseif(str.includes('Safari')){
return'safri';
}elseif(str.includes('Firefox')){
return'firefox';
}elseif(explorer.indexOf('Opera')>=0){
return'opera';
}elseif(str.includes('msie')){
return'ie';
}else{
return'other';
}
};
//迴圈判斷,將對應關係抽象為配置,更加清晰明確
functiongetBrowser(){
conststr=navigator.userAgent;
constlist=[
{key:'QQBrowser',browser:'qq'},
{key:'Chrome',browser:'chrome'},
{key:'Safari',browser:'safari'},
{key:'Firefox',browser:'firefox'},
{key:'Opera',browser:'opera'},
{key:'msie',browser:'ie'},
];
for(leti=0;i<list.length;i++){
constitem=list[i];
if(str.includes(item.key)){returnitem.browser};
}
return'other';
}
5. 提前讓函式退出代替巢狀條件分支
讓函式變成多出口
提前返回,替換巢狀條件分支
。
functiondel(obj){
varret;
if(!obj.isReadOnly){//不為只讀的才能被刪除
if(obj.isFolder){//如果是資料夾
ret=deleteFolder(obj);
}elseif(obj.isFile){//如果是檔案
ret=deleteFile(obj);
}
}
returnret;
};
functiondel(obj){
if(obj.isReadOnly){//反轉if表示式
return;
}
if(obj.isFolder){
returndeleteFolder(obj);
}
if(obj.isFile){
returndeleteFile(obj);
}
};
6. 傳遞物件引數代替過長的引數列表
函式引數過長那麼就增加出錯的風險,想保證傳遞的順序正確就是一件麻煩的事,程式碼可讀性也會變差,儘量保證函式的引數不會太長。如果必須傳遞多個引數的話,建議使用物件
代替。
一般來說,函式引數最好不要超過3個
functionsetUserInfo(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(1314,'sven','shenzhen','male','137********',377876679);
functionsetUserInfo(obj){
console.log('id='+obj.id);
console.log('name='+obj.name);
console.log('address='+obj.address);
console.log('sex='+obj.sex);
console.log('mobile='+obj.mobile);
console.log('qq='+obj.qq);
};
setUserInfo({
id:1314,
name:'sven',
address:'shenzhen',
sex:'male',
mobile:'137********',
qq:377876679
});
7. 少用三目運算子
三目運算子效能高,程式碼量少。
但不應該濫用三目運算子,我們應該在簡單邏輯分支使用,在複雜邏輯分支避免使用。
//簡單邏輯可以使用三目運算子
varglobal=typeofwindow!=="undefined"?window:this;
//複雜邏輯不適合使用
varok=isString?(isTooLang?2:(isTooShort?1:0)):-1;
8. 合理使用鏈式呼叫
優點:鏈式呼叫使用簡單,程式碼量少。
缺點:鏈式呼叫帶來的壞處就是在除錯不方便
,如果我們知道一條鏈中有錯誤出現,必須得先把這條鏈拆開才能加上一些除錯 log 或者增加斷點,這樣才能定位錯誤出現的地方。
如果該鏈條的結構相對穩定,後期不易發生修改,可以使用鏈式。
varUser={
id:null,
name:null,
setId:function(id){
this.id=id;
returnthis;
},
setName:function(name){
this.name=name;
returnthis;
}
};
User
.setId(1314)
.setName('sven');
varuser=newUser();
user.setId(1314);
user.setName('sven');
9. 分解大型類
大型類的分解和函式的提煉很像,類太大會出現邏輯不清晰,難以理解和維護的問題。
合理的大類分解可以使類的邏輯清晰,且子模組可以方便複用。
10. 活用位操作符
程式語言計算乘除的效能都不高,但是某些情況使用位操作符可以提升乘除等運算的效能。
11. 純函式
純函式是指不依賴於
且不改變
它作用域之外的變數狀態的函式。
純函式的返回值只由它呼叫時的引數決定,它的執行不依賴於系統的狀態(執行上下文)。
相同的輸入引數,一定會得到相同的輸出,也就是內部不含有會影響輸出的隨機變數。
不屬於純函式的特點:
-
更改檔案系統
-
往資料庫插入記錄
-
傳送一個 http 請求
-
可變資料
-
列印/log
-
獲取使用者輸入
-
DOM 查詢
-
訪問系統狀態
純函式的作用:
-
可靠性:函式返回永遠和預期一致
-
可快取性:因為只要輸入一樣輸出一定一樣,因此可將輸入作為key,輸出作為值,使用物件快取已經計算的結果
-
可移植性:因為沒有外部依賴,所以移植到任何環境都可正確執行
-
可測試性:方便針對函式做單元測試
-
可並行性:對一些複雜計算,可以平行計算(例如使用nodejs多個子程序同時平行計算多個任務,提高計算速度)
應用場景:
-
工具函式最好使用純函式
-
多平臺使用的程式碼(nodejs、瀏覽器、微信小程式、native客戶端等)
-
相對獨立的功能整理了一份Java面試寶典完整版PDF
vara=1;
//非純函式
functionsum(b){
returna+b;
}
//非純函式
functionsum(b){
a=2;
returnb;
}
//非純函式
functionsum(b){
returnb+Math.random();
}
//純函式
functionsum(b,c){
returnb+c;
}