5個技巧讓你更好的編寫 JavaScript(ES6) 中條件語句
使用 JavaScript 時,我們經常需要處理很多條件語句,這裡分享5個小技巧,可以讓你編寫更好/更清晰的條件語句。
1.使用 Array.includes 來處理多個條件
我們來看看下面的例子:
JavaScript 程式碼:
// condition
function test(fruit) {
if (fruit == 'apple' || fruit == 'strawberry') {
console.log('red');
}
}
乍一看,上面的例子看起來似乎沒什麼問題。 但是,如果我們還有更多的紅色水果呢?比如櫻桃(cherry)和蔓越莓(cranberries)。 我們是否要用更多的 ||
JavaScript 程式碼:
function test(fruit) {
// 條件提取到陣列中
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (redFruits.includes(fruit)) {
console.log('red');
}
}
我們將紅色水果(條件)提取到一個數組中。這樣做,可以讓程式碼看起來更整潔。
2.減少巢狀,提前使用 return 語句
讓我們擴充套件前面的示例,再包含另外兩個條件:
- 如果沒有提供水果,丟擲錯誤
- 接受水果
quantity
(數量)引數,如果超過 10,則並列印相關資訊。
JavaScript 程式碼: function test(fruit, quantity) { const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries']; // 條件 1:fruit 必須有值 if (fruit) { // 條件 2:必須為紅色 if (redFruits.includes(fruit)) { console.log('red'); // 條件 3:數量必須大於 10 if (quantity > 10) { console.log('big quantity'); } } } else { throw new Error('No fruit!'); } } // 測試結果 test(null); // 丟擲錯誤:No fruits test('apple'); // 列印:red test('apple', 20); // 列印:red,big quantity
看看上面的程式碼,我們有:
– 1 個 if / else 語句過濾掉無效條件
– 3 層 if 語句巢狀(分別是條件1,2和3)
我個人遵循的一般規則是 在發現無效條件時提前 return。
JavaScript 程式碼:
/* 在發現無效條件時提前 return */
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// 條件 1:提前丟擲錯誤
if (!fruit) throw new Error('No fruit!');
// 條件2:必須為紅色
if (redFruits.includes(fruit)) {
console.log('red');
// 條件 3:數量必須大於 10
if (quantity > 10) {
console.log('big quantity');
}
}
}
這樣做,我們可以減少一個巢狀層級。 這種編碼風格很好,特別是當你的 if
語句很長時(想象一下,你需要滾動到最底部才知道那裡有一個 else
語句,這樣程式碼的可讀性就變得很差了)。
如果通過反轉條件並提前 return ,我們可以進一步減少巢狀。 請檢視下面的條件 2 ,看看我們是如何做到的:
JavaScript 程式碼:
/* 在發現無效條件時提前 return */
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (!fruit) throw new Error('No fruit!'); // 條件 1:提前丟擲錯誤
if (!redFruits.includes(fruit)) return; // 條件 2:當 fruit 不是紅色的時候,提前 return
console.log('red');
// 條件 3:必須是大量存在
if (quantity > 10) {
console.log('big quantity');
}
}
通過反轉條件2的條件,我們的程式碼現在沒有巢狀語句了。 當我們有很長的邏輯程式碼時,這種技巧非常有用,我們希望在條件不滿足時停止下一步的處理。
然而,這並不是嚴格的規定。問問自己,這個版本(沒有巢狀)是否要比前一個版本(條件 2 有巢狀)的更好、可具可讀性?
對我來說,我會選擇前一個版本(條件 2 有巢狀)。 這是因為:
- 程式碼簡短直接,巢狀 if 更清晰
- 反轉條件可能會引發更多的思考過程(增加認知負擔)
因此,始終追求更少的巢狀,提前 return,但是不要過度。但不要過度。如果您感興趣,這裡有一篇文章和 StackOverflow 的討論, 進一步討論這個話題:
3.使用函式的預設引數 和 解構
我想下面的程式碼可能看起來很熟悉,我們在使用 JavaScript 時總是需要檢查 null
/ undefined
值並分配預設值:
JavaScript 程式碼:
function test(fruit, quantity) {
if (!fruit) return;
const q = quantity || 1; // 如果沒有提供 quantity 引數,則預設為 1
console.log(`We have ${q} ${fruit}!`);
}
// 測試結果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
實際上,我們可以通過分配預設函式引數來消除變數 q
。
JavaScript 程式碼:
function test(fruit, quantity = 1) { // i如果沒有提供 quantity 引數,則預設為 1
if (!fruit) return;
console.log(`We have ${quantity} ${fruit}!`);
}
// 測試結果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
更簡單直觀不是嗎? 請注意,每個函式引數都有自己的預設值。 例如,我們也可以為 fruit
分配一個預設值:function test(fruit = 'unknown', quantity = 1)
。
如果我們的 fruit 是一個 Object 物件怎麼辦? 我們可以指定預設引數嗎?
JavaScript 程式碼:
function test(fruit) {
// 如果有值,則列印 fruit.name
if (fruit && fruit.name) {
console.log (fruit.name);
} else {
console.log('unknown');
}
}
//測試結果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
看看上面的例子,我們想要的是如果 fruit.name
可用則列印水果名稱,否則將列印 unknown 。我們可以使用預設函式引數和解構(destructing) 來避免 fruit && fruit.name
這樣的檢查。
JavaScript 程式碼:
// 解構 —— 只獲得 name 屬性
// 引數預設分配空物件 {}
function test({name} = {}) {
console.log (name || 'unknown');
}
//測試結果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
由於我們只需要來自 fruit
的 name
屬性,我們可以使用 {name}
來解構引數,然後我們可以在程式碼中使用 name
作為變數來取代fruit.name
。
我們還將空物件 {}
指定為預設值。 如果我們不這樣做,你將在執行行測試時遇到test(undefined)
– Cannot destructure property name of 'undefined' or 'null'.
(無法解析’undefined’或’null’的屬性名稱)。 因為 undefined中 沒有 name
屬性。
如果您不介意使用第三方庫,有幾種方法可以減少空檢查:
- 使用 Facebook 開源的 idx 庫(需搭配 Babeljs)
以下是使用Lodash的示例:
JavaScript 程式碼:
// 引入 lodash 庫,我們將獲得 _.get()
function test(fruit) {
console.log(_.get(fruit, 'name', 'unknown'); // 獲取 name 屬性,如果沒有分配,則設為預設值 unknown
}
//測試結果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
您可以在這裡 執行演示程式碼 。此外,如果你喜歡函數語言程式設計(FP),您可以選擇使用Lodash fp ,Lodash的函式式能版本(方法名更改為 get
或 getOr
)。
4.選擇 Map / Object 字面量,而不是Switch語句
讓我們看看下面的例子,我們想根據顏色列印水果:
JavaScript 程式碼:
function test(color) {
// 使用 switch case 語句,根據顏色找出對應的水果
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']
上面的程式碼似乎沒有錯,但我覺得它很冗長。使用具有更清晰語法的 object 字面量可以實現相同的結果:
JavaScript 程式碼:
// 使用物件字面量,根據顏色找出對應的水果
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum']
};
function test(color) {
return fruitColor[color] || [];
}
或者,您可以使用 Map 來實現相同的結果:
JavaScript 程式碼:
// 使用 Map ,根據顏色找出對應的水果
const fruitColor = new Map()
.set('red', ['apple', 'strawberry'])
.set('yellow', ['banana', 'pineapple'])
.set('purple', ['grape', 'plum']);
function test(color) {
return fruitColor.get(color) || [];
}
Map 是 ES2015(ES6) 引入的新的物件型別,允許您儲存鍵值對。
我們是不是應該禁止使用 switch 語句呢? 不要侷限於此。 就個人而言,我儘可能使用物件字面量,但我不會設定硬規則來阻止使用 switch ,是否使用應該根據你的場景而決定。
Todd Motto 有一篇文章深入地研究了 switch語句與物件字面量,你可以在 這裡 閱讀。
重構語法
對於上面的示例,我們實際上可以使用 Array.filter
來重構我們的程式碼,以實現相同的結果。
JavaScript 程式碼:
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'strawberry', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'pineapple', color: 'yellow' },
{ name: 'grape', color: 'purple' },
{ name: 'plum', color: 'purple' }
];
function test(color) {
// 使用 Array filter ,根據顏色找出對應的水果
return fruits.filter(f => f.color == color);
}
總有不止一種方法可以達到相同的效果。對於這個例子我們展示了 4 種實現方法。編碼很有趣!
5. 使用 Array.every 和 Array.some 來處理全部/部分滿足條件
最後一個小技巧更多地是利用新的(但不是那麼新的)Javascript Array函式來減少程式碼行。檢視下面的程式碼,我們想檢查所有水果是否都是紅色的:
JavaScript 程式碼:
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
let isAllRed = true;
// 條件:所有的水果都必須是紅色
for (let f of fruits) {
if (!isAllRed) break;
isAllRed = (f.color == 'red');
}
console.log(isAllRed); // false
}
程式碼太長了!我們可以使用 Array.every
減少行數:
JavaScript 程式碼:
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
// 條件:簡短方式,所有的水果都必須是紅色
const isAllRed = fruits.every(f => f.color == 'red');
console.log(isAllRed); // false
}
乾淨多了對吧?類似的,如果我們想要檢查是否有至少一個水果是紅色的,我們可以使用 Array.some
僅用一行程式碼就實現出來。
JavaScript 程式碼:
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
// 條件:是否存在紅色的水果
const isAnyRed = fruits.some(f => f.color == 'red');
console.log(isAnyRed); // true
}
總結
讓我們一起生成更多可讀程式碼。我希望你能在本文中學到一些新東西。
就這樣。編碼快樂!