經常code review,我發現JS newbie很容易寫出一堆冗長的代碼。今天就列幾個比較常見的“解決之道”,看看如何減少JS里的條件判斷。
提前返回,少用if...else
“if...else
是編程語言的精華。——魯迅”
但是過多的嵌套,還是挺令人抓狂的。這里有一個很典型的條件嵌套:
function func(){
var result;
if( conditionA ) {
if( condintionB ) {
result = 'Success';
} else {
result = 'Error1';
}
} else {
result = 'Error2'
}
return result;
}
這種嵌套的特點就是else里的代碼塊很小,但是由于不得不做的分支語句導致多層嵌套。動動腦筋,怎樣精簡一下呢?在if里做非
判斷——條件反轉,并通過衛語句提前return else分支。
function func(){
if( !conditionA ) {
return 'Error2'
}
if( !condintionB ) {
return 'Error1'
}
return 'Success';
}
forEach優化
遍歷的時候也經常產生大量的嵌套,如下代碼所示,我們先對數組元素做一次合法性校驗,通過后再做一次新的操作,最后把操作結果追加到新數組里。
const func = (arr) => {
const res = []
arr.forEach( (e) => {
if( e !== 'Onion' ){
res.push(`${e} Run!`)
}
})
return res;
}
仔細觀察這就是一個filter加map的過程。我們不妨試試函數式編程:
const func = (arr) => {
return arr
.filer( (e) => e !== 'Onion' )
.map( (e) => `${e} Run!` );
}
多條件,用Array.includes
再舉個例子,某個頁面需要檢驗輸入type是否合法。我收到過一個MR曾經是這么寫的。
const init(type) {
if( type === 'Seminar' || type === 'Interview' ) {
console.log('valid');
}
...
console.error('invalide');
}
如果合法的類型只有兩種,代碼其實也沒啥問題。只是一般的業務很容易有后續的延展。今后將合法類型增加到10種的話,上述代碼里將是一大長串的if判斷。這種代碼可讀性極差,我們不如轉換一下思想,把非法類型儲到數組里,用Array.includes
來幫你完成冗長的判斷。之后每增加一種新的類型,只需在數組后追加新字符串就行了。
const init(type) {
const invalidArray = ['Seminar', 'Interview']
if( invalidArray.includes(type) ) {
console.log('valid');
}
...
}
使用object索引
類似的情況也出現在三元表達式里:
const dateFormat = (dateTime) => {
const format = this.$i18n.locale === 'en' ? 'mmm d, yyyy' : 'yyyy年m月d日';
return DateFormat(dateTime, format);
}
我們現階段多語言只有en
和zh
,上述代碼自然不是問題,但是也難保哪天會支持日語——ja
。這時候再寫成下面這類代碼就很搞笑了:
const format = this.$i18n.locale === 'en' ?
'mmm d, yyyy' :
(this.$i18n.locale === 'zh' ?
'yyyy年m月d日' : 'yyyy/m/d');
比較合適的寫法就是使用object鍵索引,這樣當語言業務擴展后,只需要在localeFormats
后追加新格式就行了。
const localeFormats = {
en: 'mmm d, yyyy',
zh: 'yyyy年m月d日',
ja: 'yyyy/m/d',
}
const format = localeFormats[this.$i18n.locale];
盡量少用swith
長Switch也及其難看。
export function(type) {
switch( type ) {
case 'Onion':
return func1();
case 'Garlic':
return func2();
case 'Ginger':
return func3();
default:
return () => {console.error('ERROR')};
}
}
我記得OOP設計模式里提到過:盡量使用多態和繼承代替Switch結構。JS里倒不必非得往這方面想,用Object或是Map索引來代替Switch也是極好滴!
const arr = [
['Onion', func1],
['Garlic', func2],
['Ginger', func3],
]
const def = () => {console.error('ERROR')}
const vegetable = new Map(arr);
export function(type) {
return ( vegetable.get(type) || def ).call(null);
}
Optional Chaining
Optional Chaining(以下簡稱OC)是我極力推薦的一個語法糖。我寫過一期《Javascript Optional Chaining》具體介紹它的用法,有興趣的小伙伴可以看一看,這里稍微點一下。比如我們想獲取地址里的街道信息,但是并不確定地址本身是否存在,因此只能在獲取街道前,事先判斷一下地址合法性,一般我們會這么寫:
if( address ) {
var street = address.street;
}
但假如再多一層呢,從basicInfo.address.street
這樣找下來呢?
if( basicInfo ) {
var address = basicInfo.address;
if( address ) {
var street = address.street;
}
}
上面的代碼我已經覺得很丑陋了,再多個幾層真是沒法看了。不過不用擔心,有了OC一切迎刃而解。(雖然OC還在ECMAScript stage2,但是大家可以用babel嘗鮮;babel會自動把如下源碼轉義成上面的形式)
var street = basicInfo?.address?.street;
寫在最后
自學過幾種編程語言,我感覺這類小技巧在各類語言中大同小異;實現上也許有細微差別,但基本思想都是一樣的——減少大括號的數量!!
我在面試的時候經常看到一些人寫代碼及其冗長,嵌套極多。我提醒后,得到的回復一般是:“我沒做過這種面試”,“我熟悉的是另外一種語言”等等。回過頭來再想想,這真的是好理由嗎?