重構(gòu)幾次代碼后,我總結(jié)了一些前端代碼整潔清晰的注意點
本文已獲得原作者的獨家授權(quán),有想轉(zhuǎn)載的朋友們可以在后臺聯(lián)系我申請開白哦! PS:歡迎掘友們向我投稿哦,被采用的文章還可以送你掘金精美周邊!
前言
得益于React的幫助,在近半年也是惡補了一些原生JavaScript的一些知識點,學(xué)習(xí)的同時也慢慢的思考當(dāng)前項目中的一些合理性,復(fù)盤后總結(jié)了一些項目上必須優(yōu)化的一個點,希望和大家進(jìn)行共勉,也是本次在面基時和@蘇yun小姐姐探討后的一篇收獲文,如果對大家有幫助,不妨點個贊支持一下作者吧。
什么樣的代碼算是整潔
很長一段時間,大部分前端都在抱怨一個事情前人栽樹,后人就真的涼了的一個事實,意思就是一個項目中的代碼,除了開發(fā)者本人,其他人接手會有一定的難度。因此,如果開發(fā)的人員離職了,那么這一份代碼就難逃重構(gòu)的命運了,長久下去,那么項目很容易形成一個高危項目,哪天新來的同事加了一個需求后,突然就出現(xiàn)一些奇奇怪怪的BUG。
所以,你的代碼可能看起來是這樣的,
那么,怎么樣才算是清晰整潔的代碼呢?從字面意思上來看,在代碼中整潔清晰呢?當(dāng)我們進(jìn)行大部分的開發(fā)規(guī)范的時候,比如Eslint,我們貌似只能做到當(dāng)前如下圖,整個寢室(團(tuán)隊)大體上的一個規(guī)劃完整度,但事實上,每個人寫的代碼真就如代碼風(fēng)格一般,真就整潔清晰了?

事實證明,并不是的。Eslint給予的強(qiáng)約束只能讓代碼表面看起來不是那么繚亂,這部分和代碼清晰沒有任何關(guān)系,因此清晰代碼大多數(shù)是由開發(fā)者產(chǎn)生,在不停的編碼發(fā)現(xiàn)問題 -> 解決問題 -> 總結(jié)問題。
那么下面進(jìn)入主題,分享一些基本的小思路。
函數(shù)注釋 和 TypeScript
為什么單獨將注釋排在第一梯隊?
我個人認(rèn)為好的代碼注釋一定是清晰的,它就如同商品的簡介,你可以在第一眼知道它當(dāng)前的一些信息,如作用,傳入的參數(shù),返回了什么。
你知道當(dāng)前這個常量所指向什么,你知道聲明這個變量是用來干什么的。推薦在2021年,如果你們的團(tuán)隊正在使用TypeScript,別抱怨麻煩,它對自己的代碼質(zhì)量提升是非常直觀的。
沒有注釋的代碼,在
code review大概率是會被刮目相看的一件事情
變量&常量
TS =>

JSDOC =>

函數(shù)(方法)
TS =>

JSDOC =>

以上使用了變量和函數(shù)方法的示例來進(jìn)行一些基本的演示。JsDOC是在團(tuán)隊并沒有使用TypeScript時的備選方案。
你真的知道函數(shù)方法嗎
在寫業(yè)務(wù)的時,小伙伴們很少關(guān)注一個函數(shù)方法的復(fù)雜度,這個復(fù)雜度的大小決定了他(她)人理解你代碼的一個效率度,不論是React,還是Vue,甚至于寫Node,Libray上面大多數(shù)都是函數(shù)在支撐著,因此函數(shù)會占據(jù)著WEB開發(fā)很大的一環(huán)。
那么來看下函數(shù)上,如何能使當(dāng)前的代碼調(diào)理更加的清晰。
函數(shù)SRP
對于單一原則來說,函數(shù)其實算是其中具有魄力的一員了,在大多數(shù)情況下,函數(shù)始終只用做一件事情,一段邏輯,這樣的話,在結(jié)合基本的注釋就能讓小伙伴瞬間明白你這個方法主要是用來干什么的,而不必思考是不是還做了其他的一件事情。
但是單一原則的顆粒度又是一個問題,在寫React組件的時候,如果我們采用函數(shù)單一原則,那么一個組件中的函數(shù)是海量的,所以這個時候我們就需要權(quán)衡當(dāng)前邏輯的層次了,在適當(dāng)?shù)姆秶鷥?nèi),事的大小其實也能套用在函數(shù)中,我的這個函數(shù)可能是多個函數(shù)的BFF(聚合層),或者說我這個函數(shù)本身就是用來處理一個聚合任務(wù)的。
示例:
如下函數(shù)其實就是典型的一個函數(shù)處理了兩個行為,但是你說它并不單一其實也不是的。如果給它的作用升級,它其實也只是處理一件事情,也只是處理Storage罷了。因此,SRP的局限在于開發(fā)者本身,你希望它處理的范圍是在哪一層,那么就決定了你的函數(shù)SRP做的事情夠不夠大。

那么,我們也可以寫成下面這樣,將設(shè)置和獲取拆分成為兩個不同的函數(shù)。

主動return函數(shù)(主動停止)
對于業(yè)務(wù)的開發(fā),往往一個函數(shù)中可能需要通過一些前置條件才能流向我們業(yè)務(wù)的一些核心邏輯。這一類的前置條件往往是一些條件判斷,因此,在無法滿足于這類條件的時候,后面的代碼執(zhí)行與否都沒有任何意義的,就像面試時,簡歷不滿足篩選條件,已讀未回是一個概念。
如下代碼:當(dāng)姓名(name)和年齡(age)滿足的時候,進(jìn)行個人信息的提交,不滿足時提示。那么像下面寫,好像是沒有什么問題。但是一層層的if else看上去并不是非常的清晰。

那么不妨試試下面這個方法吧。雖然兩個方法的復(fù)雜數(shù)都是5,但其實閱讀質(zhì)量是有很大不同的。方案二的實現(xiàn)將其拆分成三個步驟,當(dāng)步驟執(zhí)行到誤區(qū)時,那么這個步驟中的處理因素return就會執(zhí)行掉。

函數(shù)合并
函數(shù)合并的作用就是(減少重復(fù)代碼),大家都知道,開發(fā)者都是善于解決重復(fù)工作的小能手,喜歡一勞永逸。所以往往在寫代碼中,能夠合并的邏輯都會被獨立出來管理,如下代碼:兩個方法都調(diào)用了相同的判斷語句。

因此,如下圖,我們將相同的邏輯提取成為一個函數(shù),將公共代碼做一層剝離后,返回對應(yīng)的狀態(tài),隨后調(diào)用進(jìn)行狀態(tài)的判斷。

圈復(fù)雜度,函數(shù)衡量標(biāo)準(zhǔn)
我也是在今年了解到圈復(fù)雜度的概念,圈復(fù)雜度能夠?qū)⒑瘮?shù)的邏輯量化,用數(shù)據(jù)相對的標(biāo)注當(dāng)前函數(shù)有一個較為相對的衡量標(biāo)準(zhǔn)。
在軟件測試的概念里,圈復(fù)雜度用來衡量一個模塊判定結(jié)構(gòu)的復(fù)雜程度,數(shù)量上表現(xiàn)為線性無關(guān)的路徑條數(shù),即合理的預(yù)防錯誤所需測試的最少路徑條數(shù)。圈復(fù)雜度大說明程序代碼可能質(zhì)量低且難于測試和維護(hù),根據(jù)經(jīng)驗,程序的可能錯誤和高的圈復(fù)雜度有著很大關(guān)系。【
百度百科】
那么,在我看來圈復(fù)雜度的一些標(biāo)準(zhǔn)化是怎么樣的呢?
| 復(fù)雜度 | 代碼狀態(tài) | 維護(hù)成本 | 建議 |
|---|---|---|---|
| 1 ~ 10 | 正常 | 低 | 無 |
| 10 ~ 20 | 復(fù)雜 | 中 | 優(yōu)化邏輯,拆分子函數(shù) |
| > 29 | 難以維護(hù) | 高 | 強(qiáng)烈建議重構(gòu) |
在這里,有一個插件推薦給大家,如下圖,我清晰的知道我當(dāng)前函數(shù)的一個復(fù)雜度狀態(tài),能夠隨時的思考函數(shù)的變化的優(yōu)化方式。潛移默化下,能夠提高開發(fā)者思考當(dāng)前實現(xiàn)的優(yōu)化方式是,這個插件名稱叫做:CodeMetrics,我認(rèn)為它是對開發(fā)者有幫助的。


復(fù)雜度高的函數(shù),強(qiáng)烈建議進(jìn)行重構(gòu),因為其中80%涉及到了臟代碼,因此重新梳理邏輯重構(gòu)是必不可免的。
點擊前往VS code下載插件
狀態(tài)備注維護(hù)
什么是狀態(tài)?
信息狀態(tài)
獲取大家都經(jīng)歷過后端返回的一些字段,如status,但基本上值其實是不可讀的,除了后端和對接人之外,其他前端往往不清楚這個狀態(tài)表示了什么。甚至于久而久之,隨著需求的增加,你會好奇status中1是什么,2是什么?那么這樣避免不了二次查閱文檔。這期間花費的時間本身可以被節(jié)省掉。
后端的不可讀字段其實都來自于實體類,但是其數(shù)據(jù)表中的字段備注非常詳細(xì)。因此,后端是絕對是能夠梳理起當(dāng)前的一個狀態(tài)的。
因此在進(jìn)行狀態(tài)操作的時候,在數(shù)據(jù)聲明時加上備注注釋。如下圖,就是比較難以看懂的一個代表了:
隨著grade變化,那么下一次去改變邏輯的時候,就需要重新對grade進(jìn)行理解。

那么,我們可以做一些友好的注釋來聲明,對狀態(tài)進(jìn)行標(biāo)注

PS.當(dāng)狀態(tài)可以被描述時,往往可以如下處理,定義一個狀態(tài)對應(yīng)的數(shù)組,返回一些對應(yīng)的描述。
一般為狀態(tài)對應(yīng)某段中文的時候使用。

操作狀態(tài)
上面是一些信息狀態(tài)的處理方式,但是操作狀態(tài)往往是前端抽象出來的,舉個很簡單的例子:一個表單的創(chuàng)建頁面和編輯頁面是不是可以復(fù)用,既然是復(fù)用那么必然涉及到了一個參數(shù)來進(jìn)行判斷。
如下代碼,就是一個非常難理解的事情,1代表創(chuàng)建,2表示編輯。這是非常不推薦的一個形式。
const?action?=?1
if?(action?===?1)?{
//?創(chuàng)建
}
if?(action?===?2)?{
//?編輯
}
比較好的形式是如下:那么一下子就知道這個參數(shù)的含義是什么了。
const?action?=?'create'
if?(action?===?'create')?{
?//?創(chuàng)建
}
if?(action?===?'edit')?{
?//?編輯
}
這類狀態(tài)往往錯在頁面路徑傳值,頁面組件復(fù)用中產(chǎn)生。
使用class聚合方法,而不是object
在上面提到過一個示例,localStorage往往是需要我們自身多封裝一層的,因此這種多個不同的方法,但是他們在操作一個模型的行為,就可以進(jìn)行一個簡單的聚合分組。
在ES5時,class語法糖還沒有出來,原型類又太麻煩,那個時候就有使用object來做方法的聚合,這其實是不友好的,如下圖:

但是為了有更好的擴(kuò)展能力,單個對象其實就沒有class有優(yōu)勢了,其次class有更好的面向?qū)ο蠡A(chǔ),而object只是將函數(shù)當(dāng)成屬性來管理的,如果要基于當(dāng)前的集合做一個超集,那么object就不能勝任子集的任務(wù)了。

寫在最后,為什么不推薦自動Prettier
本次內(nèi)容算是一個小系列吧,后續(xù)可能還有其他的一些產(chǎn)出,本次文章中的內(nèi)容大多數(shù)都是偏函數(shù)方面的問題。這部分文章應(yīng)該算是脫離了業(yè)務(wù)框架的一個知識點。
在最后,我說下我對prettier的看法吧,工具本身是好的,但是看到很多文章中無不是在git hook中直接將代碼刷一次。那么,這個插件對開發(fā)者意義價值在哪里呢?還是說為了項目代碼好看故意而為之?
所以,在最后,我希望開發(fā)者們養(yǎng)成自己的一套eslint代碼規(guī)范,可以是阿里,騰訊...等大廠,也可以是eslint-plugin熱門插件,我希望是開發(fā)者(尤其是新手開發(fā)者)堅持寫下去,按照當(dāng)前團(tuán)隊的規(guī)范,細(xì)心的寫下去,寫到后面,無非就是單引號,雙引號, 幾個空格這樣的規(guī)則都交給插件去打包,這些才是插件需要干的事情。而不是將能幫助開發(fā)者的功能交給插件做一個面子工程。
不能幫助開發(fā)者成長的面子工程工具鏈,如無必須,都不推薦輕易使用。
總結(jié)
第一次脫離框架寫文章,也算是2021年的開門紅了,希望能在接下來一年的時間,給大家?guī)砀?/span>Vue,React,TypeScript,工程化相關(guān)的文章內(nèi)容,如果本文對你有幫助,看完記得點個贊哦,有問題也可以在評論區(qū)指出哦。
2021年,希望大家都能成為更好的前端開發(fā)工程師。
最后
如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:
點個「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點在看,都是耍流氓 -_-)
歡迎加我微信「huab119」拉你進(jìn)技術(shù)群,長期交流學(xué)習(xí)...
關(guān)注公眾號「前端勸退師」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。

