JavaScript降低代碼圈復(fù)雜度優(yōu)化技巧
什么是圈復(fù)雜度
圈復(fù)雜度的計(jì)算基于程序中的決策結(jié)構(gòu),如條件語(yǔ)句(if語(yǔ)句)、循環(huán)語(yǔ)句(for、while語(yǔ)句)、分支語(yǔ)句(switch語(yǔ)句)等。每當(dāng)程序流程圖中增加一個(gè)決策點(diǎn),圈復(fù)雜度就會(huì)增加1。圈復(fù)雜度的值越高,表示代碼的復(fù)雜性越大,代碼的可讀性、可測(cè)性和可維護(hù)性也會(huì)受到影響。
通常情況下,圈復(fù)雜度的推薦值應(yīng)該在1到10之間。超過(guò)10的代碼模塊可能需要進(jìn)行重構(gòu),以提高代碼的可理解性和可測(cè)試性,并降低引入錯(cuò)誤的風(fēng)險(xiǎn)。

輔助工具
VScode插件Code Metrics
VScode插件Code Metrics可以幫助我們快速發(fā)現(xiàn)那些需要優(yōu)化復(fù)雜度的代碼,安裝好插件后如下圖所示,在代碼上方會(huì)出現(xiàn)對(duì)應(yīng)的復(fù)雜度值,根據(jù)值的大小可以看出哪些代碼是急需優(yōu)化提升可讀性。

鼠標(biāo)點(diǎn)擊所提示復(fù)雜度數(shù)值的地方可以看到具體是哪些代碼影響了復(fù)雜度,可以進(jìn)行針對(duì)性的優(yōu)化。

eslint檢查
可以使用 eslint 幫助檢查代碼的圈復(fù)雜度,當(dāng)超出了某個(gè)值就會(huì)報(bào)錯(cuò)。
rules: {
complexity: [
'error',
{
max: 10
}
]
}如上面的配置就是超出了 10 就會(huì)出現(xiàn)報(bào)錯(cuò)信息。
圈復(fù)雜度的常用解決方法
函數(shù)拆分和重構(gòu),單一職責(zé)
較高的圈復(fù)雜度往往意味著函數(shù)或方法內(nèi)部有過(guò)多的決策路徑。通過(guò)將復(fù)雜的函數(shù)分解成多個(gè)小而清晰的函數(shù),可以降低每個(gè)函數(shù)的圈復(fù)雜度,并使代碼更易于理解和維護(hù)。拆分函數(shù)時(shí),可根據(jù)功能模塊或責(zé)任進(jìn)行分類,確保每個(gè)函數(shù)只負(fù)責(zé)一項(xiàng)具體的任務(wù)。
優(yōu)化前代碼:
function handle(arr) {
// 去重
let _arr=[],_arrIds=[];
for(let i=0;i<arr.length;i++){
if(_arrIds.indexOf(arr[i].id)===-1){
_arrIds.push(arr[i].id);
_arr.push(arr[i]);
}
}
// 替換
_arr.map(item=>{
for(let key in item){
if(item[key]===''){
item[key]='--';
}
}
});
// 排序
_arr.sort((item1,item2)=>item1.id-item2.id);
return _arr;
}優(yōu)化后代碼:
function removeDuplicates(arr) {
const uniqueArr = [];
const uniqueIds = [];
for(let i = 0; i < arr.length; i++) {
if(uniqueIds.indexOf(arr[i].id) === -1) {
uniqueIds.push(arr[i].id);
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
}
function replaceEmptyValues(arr) {
const processedArr = arr.map(item => {
for(let key in item) {
if(item[key] === '') {
item[key] = '--';
}
}
return item;
});
return processedArr;
}
function sortById(arr) {
const sortedArr = arr.sort((item1, item2) => item1.id - item2.id);
return sortedArr;
}
function handle(arr) {
const uniqueArr = removeDuplicates(arr);
const processedArr = replaceEmptyValues(uniqueArr);
const sortedArr = sortById(processedArr);
return sortedArr;
}以上將原始函數(shù)拆分成了三個(gè)函數(shù)。removeDuplicates 函數(shù)用于去除數(shù)組中的重復(fù)元素,replaceEmptyValues 函數(shù)用于遍歷替換空值,sortById 函數(shù)用于根據(jù) id 進(jìn)行排序。每個(gè)函數(shù)都只負(fù)責(zé)一個(gè)明確的職責(zé)。
衛(wèi)語(yǔ)句可以減少分支
對(duì)輸入條件進(jìn)行多重判斷時(shí),使用衛(wèi)語(yǔ)句可以減少分支語(yǔ)句的使用,提高代碼的可讀性和可維護(hù)性。
// 優(yōu)化前
function calculateScore(score) {
if (score < 0) {
return "Invalid score";
} else if (score < 50) {
return "Fail";
} else if (score < 70) {
return "Pass";
} else if (score < 90) {
return "Good";
} else {
return "Excellent";
}
}
// 優(yōu)化后
function calculateScore(score) {
if (score < 0) {
return "Invalid score";
}
if (score < 50) {
return "Fail";
}
if (score < 70) {
return "Pass";
}
if (score < 90) {
return "Good";
}
return "Excellent";
}通過(guò)使用衛(wèi)語(yǔ)句,我們將每個(gè)條件判斷獨(dú)立出來(lái),避免了嵌套的分支語(yǔ)句。這種優(yōu)化方式使得代碼更加清晰,每個(gè)條件判斷都獨(dú)立成為一個(gè)邏輯塊,并且消除了使用 else 的需要。這樣做不僅提高了代碼的可讀性,還方便了后續(xù)對(duì)每個(gè)條件判斷的修改和維護(hù)。
簡(jiǎn)化條件表達(dá)式
有相同邏輯代碼進(jìn)行條件合并輸出,減少條件判斷代碼,提升可讀性。
// 優(yōu)化前
function a (num) {
if (num === 0) {
return 0;
} else if (num === 1) {
return 1;
} else if (num === 2) {
return 2;
} else {
return 3;
}
}
// 優(yōu)化后
function a (num) {
if ([0, 1, 2].indexOf(num) > -1) {
return num;
} else {
return 3;
}
}
---
// 優(yōu)化前
function a() {
if (this.a == 0) return;
if (!this.b) return;
...
}
// 優(yōu)化后
function a() {
if (this.a == 0 || !this.b) return;
...
}
---
// 優(yōu)化前
function a (type) {
if (type === 'a') {
return 'String';
} else if (type === 'b') {
return 'Number';
} else if (type === 'c') {
return 'Object';
}
}
// 優(yōu)化后
function a (type) {
let obj = {
'a': 'String',
'b': 'Number',
'c': 'Object'
};
return obj[type];
}表達(dá)式邏輯優(yōu)化
邏輯計(jì)算也會(huì)增加圈復(fù)雜度,優(yōu)化一些結(jié)構(gòu)復(fù)雜的邏輯表達(dá)式,減少不必要的邏輯判斷,也將一定程度上降低圈復(fù)雜度。
// 優(yōu)化前 a && b || a && c // 優(yōu)化后 a && (b || c)
通過(guò)多態(tài)方式替代條件式。
通過(guò)多態(tài)方式替代條件式是一種優(yōu)化技巧,多態(tài)允許我們根據(jù)不同的類型執(zhí)行不同的操作,而不需要使用復(fù)雜的條件判斷邏輯。
優(yōu)化前的代碼:
class Shape {
constructor(type) {
this.type = type;
}
calculateArea() {
if (this.type === "circle") {
// 計(jì)算圓形的面積
} else if (this.type === "rectangle") {
// 計(jì)算矩形的面積
} else if (this.type === "triangle") {
// 計(jì)算三角形的面積
}
}
}優(yōu)化后的代碼:
class Shape {
calculateArea() {
throw new Error("calculateArea() method must be implemented");
}
}
class Circle extends Shape {
calculateArea() {
// 計(jì)算圓形的面積
}
}
class Rectangle extends Shape {
calculateArea() {
// 計(jì)算矩形的面積
}
}
class Triangle extends Shape {
calculateArea() {
// 計(jì)算三角形的面積
}
}使用多態(tài)的方式,我們可以通過(guò)調(diào)用相應(yīng)對(duì)象的calculateArea方法來(lái)執(zhí)行特定形狀的面積計(jì)算,而無(wú)需使用復(fù)雜的條件判斷邏輯。
替換算法,優(yōu)化復(fù)雜度
當(dāng)發(fā)現(xiàn)某個(gè)算法的時(shí)間復(fù)雜度較高時(shí),可以考慮替換為一個(gè)具有更優(yōu)時(shí)間復(fù)雜度的算法,以提高代碼的性能。
// 優(yōu)化前
function findDuplicates(nums) {
let duplicates = [];
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] === nums[j]) {
duplicates.push(nums[i]);
}
}
}
return duplicates;
}
// 優(yōu)化后
function findDuplicates(nums) {
let freq = {};
let duplicates = [];
for (let num of nums) {
if (freq[num]) {
duplicates.push(num);
} else {
freq[num] = true;
}
}
return duplicates;
}需要注意的是,優(yōu)化算法并不總是適用于所有情況。在選擇替代算法時(shí),應(yīng)該綜合考慮數(shù)據(jù)規(guī)模、特定問(wèn)題的特性以及算法的復(fù)雜度等因素。
分解條件式,拆分函數(shù)
當(dāng)遇到復(fù)雜的條件判斷式或函數(shù)時(shí),可以考慮將其分解為更小的部分,以提高代碼的可讀性和維護(hù)性。
優(yōu)化前代碼:
function calculateScore(player) {
if (player.score >= 100 && player.level === "expert") {
return player.score * 2;
} else if (player.score >= 50 || player.level === "intermediate") {
return player.score * 1.5;
} else {
return player.score;
}
}優(yōu)化后代碼:
function hasHighScore(player) {
return player.score >= 100 && player.level === "expert";
}
function hasIntermediateScore(player) {
return player.score >= 50 || player.level === "intermediate";
}
function calculateScore(player) {
if (hasHighScore(player)) {
return player.score * 2;
} else if (hasIntermediateScore(player)) {
return player.score * 1.5;
} else {
return player.score;
}
}將原始的復(fù)雜條件判斷式拆分成了兩個(gè)獨(dú)立的函數(shù):hasHighScore和hasIntermediateScore。這樣calculateScore函數(shù)中的條件判斷變得更加清晰和可讀。通過(guò)分解條件式和拆分函數(shù),我們可以提高代碼的可讀性、可維護(hù)性和重用性。
減少return出現(xiàn)
當(dāng)前大多數(shù)圈復(fù)雜度計(jì)算工具對(duì)return個(gè)數(shù)也進(jìn)行計(jì)算,如果要針對(duì)這些工具衡量規(guī)則進(jìn)行優(yōu)化,減少return語(yǔ)句個(gè)數(shù)也為一種方式。
// 優(yōu)化前
function a(){
const value = getSomething();
if(value) {
return true;
} else {
return false;
}
}
// 優(yōu)化后
function a() {
return getSomething();
}移除控制標(biāo)記,減少變量
移除控制標(biāo)記可以使代碼更加簡(jiǎn)潔、可讀性更高,并且減少了不必要的變量使用。
優(yōu)化前的代碼:
function findFirstPositive(numbers) {
let found = false;
let firstPositive = null;
for (let num of numbers) {
if (num > 0) {
found = true;
firstPositive = num;
break;
}
}
if (found) {
return firstPositive;
} else {
return -1;
}
}優(yōu)化后的代碼:
function findFirstPositive(numbers) {
for (let num of numbers) {
if (num > 0) {
return num;
}
}
return -1;
}在優(yōu)化后的代碼中,我們直接在找到第一個(gè)正數(shù)后立即返回結(jié)果,而無(wú)需使用控制標(biāo)記和額外的變量。如果遍歷完整個(gè)數(shù)組后仍未找到正數(shù),則返回-1。
最后
如果只是刻板的使用圈復(fù)雜度的算法去衡量一段代碼的清晰度,這并不可取。在重構(gòu)系統(tǒng)時(shí),我們可以使用代碼圈復(fù)雜度工具來(lái)統(tǒng)計(jì)代碼的復(fù)雜度,并對(duì)復(fù)雜度較高的代碼進(jìn)行具體的場(chǎng)景分析。但不是說(shuō)一定要將復(fù)雜度優(yōu)化到某種程度,應(yīng)該根據(jù)實(shí)際的業(yè)務(wù)情況做出優(yōu)化決策。
以上就是JavaScript降低代碼圈復(fù)雜度優(yōu)化技巧的詳細(xì)內(nèi)容,更多關(guān)于JavaScript代碼圈復(fù)雜度的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
原生js實(shí)現(xiàn)隨機(jī)點(diǎn)餐效果
一款十分簡(jiǎn)單的原生js實(shí)現(xiàn)的隨機(jī)點(diǎn)菜代碼,點(diǎn)擊點(diǎn)菜按鈕隨機(jī)點(diǎn)取上面菜單的菜品,可根據(jù)需求改成自己需要功能,比如說(shuō)隨機(jī)點(diǎn)名。感興趣的朋友來(lái)參考實(shí)現(xiàn)代碼吧2019-12-12
javascript實(shí)現(xiàn)鼠標(biāo)移到Image上方時(shí)顯示文字效果的方法
這篇文章主要介紹了javascript實(shí)現(xiàn)鼠標(biāo)移到Image上方時(shí)顯示文字效果的方法,涉及javascript鼠標(biāo)事件及圖文屬性動(dòng)態(tài)設(shè)置的相關(guān)技巧,可用于為圖片增加文字提示效果,需要的朋友可以參考下2015-08-08
微信小程序?qū)崿F(xiàn)打開(kāi)并下載服務(wù)器上面的pdf文件到手機(jī)
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)打開(kāi)并下載服務(wù)器上面的pdf文件到手機(jī),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09
weui中的picker使用js進(jìn)行動(dòng)態(tài)綁定數(shù)據(jù)問(wèn)題
這篇文章主要介紹了weui中的picker使用js進(jìn)行動(dòng)態(tài)綁定數(shù)據(jù)問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11
js獲取或設(shè)置當(dāng)前窗口url參數(shù)的小例子
這篇文章介紹了js獲取或設(shè)置當(dāng)前窗口url參數(shù)的小例子,有需要的朋友可以參考一下2013-10-10

