1. 程式人生 > 實用技巧 >5個小技巧讓你寫出更好的JavaScript

5個小技巧讓你寫出更好的JavaScript

在使用JavaScript時,我們常常要寫不少的條件語句。這裡有五個小技巧,可以讓你寫出更乾淨、漂亮的條件語句。
使用Array.includes來處理多重條件
舉個栗子:
//條件語句
functiontest(fruit){
if(fruit=='apple'||fruit=='strawberry'){
console.log('red');
}
}
乍一看,這麼寫似乎沒什麼大問題。
然而,如果我們想要匹配更多的紅色水果呢,比方說『櫻桃』和『蔓越莓』?我們是不是得用更多的||來擴充套件這條語句?
我們可以使用Array.includes重寫以上條件句。
functiontest(fruit){
//把條件提取到陣列中
constredFruits=['apple','strawberry','cherry','cranberries'];
if(redFruits.includes(fruit)){
console.log('red');
}
}
我們把紅色的水果(條件)都提取到一個數組中,這使得我們的程式碼看起來更加整潔。

少寫巢狀,儘早返回
讓我們為之前的例子新增兩個條件:
如果沒有提供水果,丟擲錯誤;
如果該水果的數量大於10,將其打印出來。
functiontest(fruit,quantity){
constredFruits=['apple','strawberry','cherry','cranberries'];
//條件1:fruit必須有值
if(fruit){
//條件2:必須為紅色
if(redFruits.includes(fruit)){
console.log('red');
//條件3:必須是大量存在
if(quantity>10){
console.log('bigquantity');
}
}
}else{
thrownewError('Nofruit!');
}
}
//測試結果
test(null);//報錯:Nofruits
test('apple');//列印:red
test('apple',20);//列印:red,bigquantity
讓我們來仔細看看上面的程式碼,我們有:
1個if/else語句來篩選無效的條件;
3層if語句巢狀(條件1,2&3)。

[plain]view plaincopy
  1. JavaScript(簡稱“JS”)是一種具有函式優先的輕量級,解釋型或即時編譯型的高階程式語言。雖然它是作為開發Web頁面的指令碼語言而出名的,讀書筆記https://www.yuananren.com但是它也被用到了很多非瀏覽器環境中,JavaScript基於原型程式設計、多正規化的動態指令碼語言,並且支援面向物件、命令式和宣告式(如函數語言程式設計)風格。
  2. 就我個人而言,我遵循的一個總的規則是當發現無效條件時儘早返回。

/當發現無效條件時儘早返回/
functiontest(fruit,quantity){
constredFruits=['apple','strawberry','cherry','cranberries'];
//條件1:儘早丟擲錯誤
if(!fruit)thrownewError('Nofruit!');
//條件2:必須為紅色
if(redFruits.includes(fruit)){
console.log('red');
//條件3:必須是大量存在
if(quantity>10){
console.log('bigquantity');
}
}
}
如此一來,我們就少寫了一層巢狀。這是種很好的程式碼風格,尤其是在if語句很長的時候(試想一下,你得滾動到底部才能知道那兒還有個else語句,是不是有點不爽)。
如果反轉一下條件,我們還可以進一步地減少巢狀層級。注意觀察下面的條件2語句,看看是如何做到這點的:
/當發現無效條件時儘早返回/
functiontest(fruit,quantity){
constredFruits=['apple','strawberry','cherry','cranberries'];
if(!fruit)thrownewError('Nofruit!');//條件1:儘早丟擲錯誤
if(!redFruits.includes(fruit))return;//條件2:當fruit不是紅色的時候,直接返回
console.log('red');
//條件3:必須是大量存在
if(quantity>10){
console.log('bigquantity');
}
}
通過反轉條件2的條件,現在我們的程式碼已經沒有嵌套了。
當我們程式碼的邏輯鏈很長,並且希望當某個條件不滿足時不再執行之後流程時,這個技巧會很好用。
然而,並沒有任何硬性規則要求你這麼做。這取決於你自己,對你而言,這個版本的程式碼(沒有巢狀)是否要比之前那個版本(條件2有巢狀)的更好、可讀性更強?
是我的話,我會選擇前一個版本(條件2有巢狀)。原因在於:
這樣的程式碼比較簡短和直白,一個巢狀的if使得結構更加清晰;
條件反轉會導致更多的思考過程(增加認知負擔)。
因此,始終追求更少的巢狀,更早地返回,但是不要過度。
感興趣的話,這裡有篇關於這個問題的文章以及StackOverflow上的討論:
AvoidElse,ReturnEarlybyTimOxley
StackOverflowdiscussiononif/elsecodingstyle
使用函式預設引數和解構
我猜你也許很熟悉以下的程式碼,在JavaScript中我們經常需要檢查null/undefined並賦予預設值:
functiontest(fruit,quantity){
if(!fruit)return;
constq=quantity||1;//如果沒有提供quantity,預設為1
console.log(

Wehave${q}${fruit}!);
}
//測試結果
test('banana');//Wehave1banana!
test('apple',2);//Wehave2apple!
事實上,我們可以通過函式的預設引數來去掉變數q。
functiontest(fruit,quantity=1){//如果沒有提供quantity,預設為1
if(!fruit)return;
console.log(Wehave${quantity}${fruit}!);
}
//測試結果
test('banana');//Wehave1banana!
test('apple',2);//Wehave2apple!
是不是更加簡單、直白了?
請注意,所有的函式引數都可以有其預設值。舉例來說,我們同樣可以為fruit賦予一個預設值:
functiontest(fruit=‘unknown’,quantity=1)。
那麼如果fruit是一個物件(Object)呢?我們還可以使用預設引數嗎?
functiontest(fruit){
//如果有值,則打印出來
if(fruit&&fruit.name){
console.log(fruit.name);
}else{
console.log('unknown');
}
}
//測試結果
test(undefined);//unknown
test({});//unknown
test({name:'apple',color:'red'});//apple
觀察上面的例子,當水果名稱屬性存在時,我們希望將其打印出來,否則列印『unknown』。
我們可以通過預設引數和解構賦值的方法來避免寫出fruit&&fruit.name這種條件。
//解構——只得到name屬性
//預設引數為空物件{}
functiontest({name}={}){
console.log(name||'unknown');
}
//測試結果
test(undefined);//unknown
test({});//unknown
test({name:'apple',color:'red'});//apple
既然我們只需要fruit的name屬性,我們可以使用{name}來將其解構出來,之後我們就可以在程式碼中使用name變數來取代fruit.name。
我們還使用{}作為其預設值。
如果我們不這麼做的話,
在執行test(undefined)時,你會得到一個錯誤Cannotdestructurepropertynameof‘undefined’or‘null’.,
因為undefined上並沒有name屬性。
(譯者注:這裡不太準確,其實因為解構只適用於物件(Object),而不是因為undefined上並沒有name屬性(空物件上也沒有)。參考解構賦值-MDN)
如果你不介意使用第三方庫的話,有一些方法可以幫助減少空值(null)檢查:
使用Lodashget函式;
使用Facebook開源的idx庫(需搭配Babeljs)。
這裡有一個使用Lodash的例子:
//使用lodash庫提供的方法
functiontest(fruit){
//獲取屬性name的值,如果沒有,設為預設值unknown
console.log(.get(fruit,'name','unknown');
}
//測試結果
test(undefined);//unknown
test({});//unknown
test({name:'apple',color:'red'});//apple
你可以在這裡執行演示程式碼。
另外,如果你偏愛函數語言程式設計(FP),你可以選擇使用Lodashfp——函式式版本的Lodash(方法名變為get或getOr)。
相較於switch,Map/Object也許是更好的選擇
讓我們看下面的例子,我們想要根據顏色打印出各種水果:
functiontest(color){
//使用switchcase來找到對應顏色的水果
switch(color){
case'red':
return['apple','strawberry'];
case'yellow':
return['banana','pineapple'];
case'purple':
return['grape','plum'];
default:
return[];
}
}
//測試結果
test(null);//[]
test('yellow');//['banana','pineapple']
上面的程式碼看上去並沒有錯,但是就我個人而言,它看上去很冗長。同樣的結果可以通過物件字面量來實現,語法也更加簡潔:
//使用物件字面量來找到對應顏色的水果
constfruitColor={
red:['apple','strawberry'],
yellow:['banana','pineapple'],
purple:['grape','plum']
};
functiontest(color){
returnfruitColor[color]||[];
}
或者,你也可以使用Map來實現同樣的效果:
//使用Map來找到對應顏色的水果
constfruitColor=newMap()
.set('red',['apple','strawberry'])
.set('yellow',['banana','pineapple'])
.set('purple',['grape','plum']);
functiontest(color){
returnfruitColor.get(color)||[];
}
Map是ES2015引入的新的物件型別,允許你存放鍵值對。
那是不是說我們應該禁止使用switch語句?別把自己限制住。
我自己會在任何可能的時候使用物件字面量,但是這並不是說我就不用switch,這得視場景而定。
ToddMotto有一篇文章深入討論了switch語句和物件字面量,你也許會想看看。
懶人版:重構語法
就以上的例子,事實上我們可以通過重構我們的程式碼,使用Array.filter實現同樣的效果。
constfruits=[
{name:'apple',color:'red'},
{name:'strawberry',color:'red'},
{name:'banana',color:'yellow'},
{name:'pineapple',color:'yellow'},
{name:'grape',color:'purple'},
{name:'plum',color:'purple'}
];
functiontest(color){
//使用Arrayfilter來找到對應顏色的水果
returnfruits.filter(f=>f.color==color);
}
解決問題的方法永遠不只一種。對於這個例子我們展示了四種實現方法。
Codingisfun!
使用Array.every和Array.some來處理全部/部分滿足條件
最後一個小技巧更多地是關於使用新的(也不是很新了)JavaScript陣列函式來減少程式碼行數。
觀察以下的程式碼,我們想要檢查是否所有的水果都是紅色的:
constfruits=[
{name:'apple',color:'red'},
{name:'banana',color:'yellow'},
{name:'grape',color:'purple'}
];
functiontest(){
letisAllRed=true;
//條件:所有的水果都必須是紅色
for(letfoffruits){
if(!isAllRed)break;
isAllRed=(f.color=='red');
}
console.log(isAllRed);//false
}
這段程式碼也太長了!我們可以通過Array.every來縮減程式碼
constfruits=[
{name:'apple',color:'red'},
{name:'banana',color:'yellow'},
{name:'grape',color:'purple'}
];
functiontest(){
//條件:(簡短形式)所有的水果都必須是紅色
constisAllRed=fruits.every(f=>f.color=='red');
console.log(isAllRed);//false
}
清晰多了對吧?
類似的,如果我們想要檢查是否有至少一個水果是紅色的,我們可以使用Array.some僅用一行程式碼就實現出來。
constfruits=[
{name:'apple',color:'red'},
{name:'banana',color:'yellow'},
{name:'grape',color:'purple'}
];
functiontest(){
//條件:至少一個水果是紅色的
constisAnyRed=fruits.some(f=>f.color=='red');
console.log(isAnyRed);//true
}
讓我們一起寫出可讀性更高的程式碼吧。希望這篇文章能給你們帶來一些幫助。就是這樣啦~Happycoding