這6個(gè)令人窒息的爛代碼,你看完都忍不了(新人操作)
最近進(jìn)行代碼 review,發(fā)現(xiàn)團(tuán)隊(duì)中部分新人寫(xiě)的代碼比較亂,有一個(gè)新人竟然寫(xiě)出了下面的代碼:

真是令人哭笑不得,我說(shuō)你這是在放大招嗎?

這里節(jié)選了團(tuán)隊(duì)中六則糟糕代碼的案例進(jìn)行分析:
案例一
變量、屬性和函數(shù)名應(yīng)該使用小駝峰式命名法,并且名稱是可描述的. 應(yīng)該避免使用單字符變量和不通用的縮寫(xiě)。
某前端同學(xué)的 angular 代碼:
export?class?PageComponent?implements?OnChanges?{
??@Input()?pageObj
??@Input()?currentPage???=?0?
??goPage
??cg:?any?=?false
??goToPage()?{
????if?(!this.goPage)?{
??????return
????}
????this.currentPage?=?+this.goPage
????this.pageChange.emit(this.goPage)
??}
}
該同學(xué)定義了一個(gè)變量叫?cg
,不符合變量名可描述的規(guī)則,除了本人之外團(tuán)隊(duì)其他成員看不懂其含義。goToPage
?和?goPage
?容易混淆,語(yǔ)義也不明確。
案例二
盡量使用 es6 語(yǔ)法簡(jiǎn)化代碼邏輯
某后端同學(xué)的 js 代碼:
let?startDay?=?0?
let?endDay?=?1??
switch?(query.birth)?{
????case? 0~1 :??//當(dāng)天過(guò)生日
??????startDay?=?0
??????endDay?=?1
??????break
????case? 1~8 :??//1~8天過(guò)生日
??????startDay?=?1
??????endDay?=?8
??????break
????case? 8~16 :??//8~16天過(guò)生日
??????startDay?=?8
??????endDay?=?16
??????break
????case? 16~31 :??//16~31天過(guò)生日
??????startDay?=?16
??????endDay?=?31
??????break
????case? 31~999 :??//31天以后天過(guò)生日
??????startDay?=?31
??????endDay?=?999
??????break
}
寫(xiě)了20多行,其實(shí)就是一句話能搞定的事情,基本功太差:
let?[startDay,?endDay]?=?query.birth.split( ~ ).map(it?=>?+it)
案例三
使用?
/** ... */
?作為多行注釋。包含描述、指定所有參數(shù)和返回值的類型和值。/**?
*?函數(shù)說(shuō)明?
*?@關(guān)鍵字?
*/使用?
//
?作為單行注釋。在評(píng)論對(duì)象上面另起一行使用單行注釋。在注釋前插入空行。
某前端同學(xué)的 angular 代碼:
/**處理右上角btn操作**/
handleWithBtn(btn)?{
??switch?(btn)?{
????case? export :?{?//?批量認(rèn)證
??????Debug.log( 導(dǎo)出 )
??????break
????}
??}
}
上面的注釋既不規(guī)范,也是多余的,當(dāng)起了一個(gè)好的名字之后,代碼就已經(jīng)非常明確了。
案例四
邏輯互斥的 if 語(yǔ)句一定要配合 else 或 return 使用,把概率高的寫(xiě)在前面。
某后端同學(xué)的 js 代碼:
if?(productClass?===? Card ?&&?action?===?BUYCARD)?{
??seneca.sendSms(smsData,?params)
}
if?(productClass?===? Card ?&&?action?===?TURNCARD)?{
??seneca.patchStatus(productId)
}
if?(productClass?===? Card ?&&?action?===?REPLACE)?{
??seneca.changeStatus( crm ,? Card )
}
if?(productClass?===? Lesson )?{
??seneca.changeStatus( course ,? Lesson )
}
...
上面每個(gè)判斷都要執(zhí)行一次,完全沒(méi)有必要,這種情況下要么使用 switch 要么 if 配合 else 或 return 使用。
案例五
保持函數(shù)簡(jiǎn)短,一個(gè)好的函數(shù)適合展現(xiàn)在一個(gè)幻燈片(slide)上,這樣如果在一個(gè)比較大房間中,也便于最后一排的人閱讀。每一個(gè)函數(shù)的代碼應(yīng)該限制在 15 行左右,另外為了避免 if 語(yǔ)句過(guò)度嵌套, 應(yīng)該提前將函數(shù)值返回.
某前端同學(xué)為了去除 params 對(duì)象中的 value 為 null, ?,undefined 的 key 寫(xiě)的代碼:
getUrlParam(sUrl,?sKey)?{
??const?param?=?sUrl.split( # )[0].split( ? )[1]
??if?(param)?{
????if?(sKey)?{???????//?指定參數(shù)名稱
??????const?strs?=?param.split( & )
??????const?arrs?=?new?Array()??//?如果存在多個(gè)同名參數(shù),則返回?cái)?shù)組
??????for?(let?i?=?0,?len?=?strs.length;?i?<?len;?i++)?{
????????const?tmp?=?strs[i].split( = )
????????if?(tmp[0]?===?sKey)?{
??????????arrs.push(tmp[1])
????????}
??????}
??????if?(arrs.length?===?1)?{//?返回該參數(shù)的值或者空字符串
????????return?arrs[0]
??????}?else?if?(arrs.length?===?0)?{
????????return? ?
??????}?else?{
????????return?arrs
??????}
????}?else?{//?不指定參數(shù)名稱,返回全部的參數(shù)對(duì)象?或者?{}
??????if?(param?===?undefined?||?param?===? ?)?{
????????return?{}
??????}?else?{
????????const?strs?=?param.split( & )
????????const?arrObj?=?new?Object()
????????for?(let?i?=?0,?len?=?strs.length;?i?<?len;?i++)?{
??????????const?tmp?=?strs[i].split( = )
??????????if?(!(tmp[0]?in?arrObj))?{
????????????arrObj[tmp[0]]?=?[]
??????????}
??????????arrObj[tmp[0]].push(tmp[1])
????????}
????????return?arrObj
??????}
????}
??}?else?{
????return? ?
??}
}
這種函數(shù)可維護(hù)性極差,自己寫(xiě)的過(guò)個(gè)星期也讀不懂什么意思了,出現(xiàn)錯(cuò)誤很難定位。下面是改造后的:
function?filterParams(obj)?{
??const?keys?=?Object.keys(obj)
??keys.forEach(key?=>?{
????const?value?=?obj[key]
????if?(isObject(value))?filterParams(value)
????if?(isEmpty(value))?delete?obj[key]
??})
??return?obj
}
function?isEmpty(input)?{
??return?[ ?,?undefined,?null].includes(input)
}
function?isObject(input)?{
??return?input?!==?null?&&?(!Array.isArray(input))?&&?typeof?input?===? object
}
明顯清晰很多,可讀性很強(qiáng),邏輯也很健壯。如果你覺(jué)得一個(gè) 15 行以內(nèi)的函數(shù)搞不定某個(gè)事情,就把它拆分成多個(gè)小于 15 行的函數(shù)。
案例六
配置要寫(xiě)在配置文件里面統(tǒng)一管理,常量也要定義在單獨(dú)的文件里面,常量名全部大寫(xiě)。
某后端同學(xué)寫(xiě)的 js 代碼:
let?client?=?new?TopClient({
?? appkey :? 12345678 ,
?? appsecret :? asdfasdfasdfasdfasdfasdf ,
?? REST_URL :? http://gw.api.taobao.com/router/rest
})
?let?sign?=?handler.sign(data,? qwerqwerqwerqwerqwer )
?...
密鑰這種配置信息寫(xiě)在代碼里面,既不方便測(cè)試,又不利于拓展