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-12javascript實(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-09weui中的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-11js獲取或設(shè)置當(dāng)前窗口url參數(shù)的小例子
這篇文章介紹了js獲取或設(shè)置當(dāng)前窗口url參數(shù)的小例子,有需要的朋友可以參考一下2013-10-10