轉(zhuǎn)譯自:https://scotch.io/tutorials/5-tips-to-write-better-conditionals-in-javascript
When working with JavaScript, we deal a lot with conditionals, here are the 5 tips for you to write better / cleaner conditionals.
在使用 JavaScript 時,我們會處理很多條件語句,這里有 5 個技巧可以幫助您編寫更好旬迹、更簡潔的條件語句。
1驹马、Use Array.includes for Multiple Criteria(對多個條件使用 Array.includes)
Let's take a look at the example below:
讓我們看看下面的例子:
// condition
function test(fruit) {
if (fruit == 'apple' || fruit == 'strawberry') {
console.log('red');
}
}
At first glance, the above example looks good. However, what if we get more red fruits, say cherry and cranberries? Are we going to extend the statement with more || ?
乍一看,上面的例子看起來不錯。然而,如果還有更多紅顏色的水果需要判斷呢溶褪,比如櫻桃和小紅莓践险,我們要用更多的 || 來擴展這個表述嗎吹菱?
We can rewrite the conditional above by using Array.includes
我們可以用 Array.includes 重寫上面的條件彭则。可參見 Array.includes 相關(guān)文檔
function test(fruit) {
// extract conditions to array
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (redFruits.includes(fruit)) {
console.log('red');
}
}
We extract the red fruits (conditions) to an array. By doing this, the code looks tidier.
我們將紅色水果(條件)提取到一個數(shù)組中毁葱。這樣做之后贰剥,代碼看起來更整潔。
2蚌成、Less Nesting, Return Early(更少的嵌套前痘,盡早返回)
Let's expand the previous example to include two more conditions:
讓我們擴展前面的示例,以包含另外兩個條件:
- if no fruit provided, throw error
如果沒有提供水果(名稱)担忧,拋出錯誤。
- accept and print the fruit quantity if exceed 10.
如果(紅色水果)數(shù)量超過 10 個最欠,接受并打印惩猫。
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// condition 1: fruit must has value
if (fruit) {
// condition 2: must be red
if (redFruits.includes(fruit)) {
console.log('red');
// condition 3: must be big quantity
if (quantity > 10) {
console.log('big quantity');
}
}
} else {
throw new Error('No fruit!');
}
}
// test results
test(null); // error: No fruits
test('apple'); // print: red
test('apple', 20); // print: red, big quantity
Look at the code above, we have:
看看上面的代碼轧房,我們有:
- 1 if/else statement that filter out invalid condition
1 組過濾無效條件的 if/else 語句
- 3 levels of nested if statement (condition 1, 2 & 3)
3 層的 if 嵌套語句(條件 1、2 和 3)
A general rule I personally follow is return early when invalid conditions found.
我個人遵循的一般規(guī)則是迟赃,當發(fā)現(xiàn)無效條件時厂镇,提前返回。
/_ return early when invalid conditions found _/
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// condition 1: throw error early
if (!fruit) throw new Error('No fruit!');
// condition 2: must be red
if (redFruits.includes(fruit)) {
console.log('red');
// condition 3: must be big quantity
if (quantity > 10) {
console.log('big quantity');
}
}
}
By doing this, we have one less level of nested statement. This coding style is good especially when you have long if statement (imagine you need to scroll to the very bottom to know there is an else statement, not cool).
這樣酌媒,我們就少了一層嵌套馍佑。這種編碼風格很好梨水,尤其是當你有很長的 if 語句時(想象一下疫诽,你需要滾動到最底部才能知道還有一個 else 語句舅世,這并不酷)雏亚。
We can further reduce the nesting if, by inverting the conditions & return early. Look at condition 2 below to see how we do it:
通過反轉(zhuǎn)條件和提早返回,我們可以進一步減少嵌套查辩⊥郑看看下面的條件 2功舀,我們是怎么做的:
/_ return early when invalid conditions found _/
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (!fruit) throw new Error('No fruit!'); // condition 1: throw error early
if (!redFruits.includes(fruit)) return; // condition 2: stop when fruit is not red
console.log('red');
// condition 3: must be big quantity
if (quantity > 10) {
console.log('big quantity');
}
}
By inverting the conditions of condition 2, our code is now free of a nested statement. This technique is useful when we have long logic to go and we want to stop further process when a condition is not fulfilled.
通過反轉(zhuǎn)條件 2 的條件,我們的代碼現(xiàn)在沒有嵌套語句列敲。當我們有很長的邏輯要處理時帖汞,這種技術(shù)是有用的涨冀,當一個條件沒有滿足時麦萤,我們想要停止進一步的處理壮莹。
However, that's no hard rule for doing this. Ask yourself, is this version (without nesting) better / more readable than the previous one (condition 2 with nested)?
然而,這并不是嚴格的規(guī)則涝滴。問問自己胶台,這個版本(沒有嵌套)是否比前一個版本(嵌套的條件 2)更好、更易讀韩脏?
For me, I would just leave it as the previous version (condition 2 with nested). It is because:
對于我來說铸磅,我將把它保留為以前的版本(條件 2 和嵌套)。這是因為:
- the code is short and straight forward, it is clearer with nested if
代碼簡短而直接弧械,如果嵌套空民,代碼就更清晰了
- inverting condition may incur more thinking process (increase cognitive load)
反轉(zhuǎn)條件可能會導(dǎo)致更多的思考過程(增加認知負擔)
Therefore, always aims for Less Nesting and Return Early but don't overdo it. There is an article & StackOverflow discussion that talks further on this topic if you interested:
因此,總是以更少的嵌套及盡早返回為目標唁桩,但不要過度荒澡。如果你感興趣的話与殃,StackOverflow 有一篇相關(guān)的文章討論了這個話題:
- Avoid Else, Return Early by Tim Oxley
Tim Oxley 的文章,避免 Else米奸,盡早返回
- StackOverflow discussion on if/else coding style
StackOverflow 基于 if/else 編碼風格的討論
3悴晰、Use Default Function Parameters and Destructuring(使用默認的函數(shù)參數(shù)和解構(gòu))
I guess the code below might look familiar to you, we always need to check for null / undefined value and assign default value when working with JavaScript:
我想下面的代碼對您來說可能很熟悉逐工,我們在使用 JavaScript 時總是需要檢查 null 或 undefined 值并分配默認值:
function test(fruit, quantity) {
if (!fruit) return;
const q = quantity || 1; // if quantity not provided, default to one
console.log(`We have ${q} ${fruit}!`);
}
//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
In fact, we can eliminate the variable q
by assigning default function parameters.
事實上泪喊,我們可以通過指定默認的函數(shù)參數(shù)來消除變量 q
。
function test(fruit, quantity = 1) { // if quantity not provided, default to one
if (!fruit) return;
console.log(`We have ${quantity} ${fruit}!`);
}
//test results
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
Much easier & intuitive isn't it? Please note that each parameter can has it own default function parameter. For example, we can assign default value to fruit
too: function test(fruit = 'unknown', quantity = 1)
.
更簡單和直觀哈扮,不是嗎滑肉?請注意摘仅,每個參數(shù)都可以有自己的默認函數(shù)參數(shù)。例如惶洲,我們也可以為 fruit
賦值:function test(fruit = 'unknown', quantity = 1)
签则。
What if our fruit
is an object? Can we assign default parameter?
如果我們的 fruit
是一個對象呢渐裂?我們可以指定默認參數(shù)嗎钠惩?
function test(fruit) {
// printing fruit name if value provided
if (fruit && fruit.name) {
console.log (fruit.name);
} else {
console.log('unknown');
}
}
//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
Look at the example above, we want to print the fruit name if it's available or we will print unknown. We can avoid the conditional fruit && fruit.name checking with default function parameter & destructing.
請看上面的示例篓跛,如果 fruit.name
是可用的,我們將打印該水果名稱蔬咬,否則我們將打印 unknown
沐寺。我們可以避免使用與默認函數(shù)參數(shù)和解構(gòu)對條件 fruit && fruit.name
進行檢查混坞。
// destructing - get name property only
// assign default empty object {}
function test({name} = {}) {
console.log (name || 'unknown');
}
//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
Since we only need property name
from fruit, we can destructure the parameter using {name}
, then we can use name
as variable in our code instead of fruit.name
.
因為我們只需要水果中的屬性 name
,所以我們可以使用 {name}
來解構(gòu)啥酱,然后我們可以在代碼中使用 name
作為變量蚊俺,而不是 fruit.name
泳猬。
We also assign empty object {}
as default value. If we do not do so, you will get error when executing the line test(undefined)
- Cannot destructure property name of undefined
or null
. because there is no name
property in undefined.
我們還將空對象 {}
指定為默認值宇植。如果我們不這樣做指郁,當執(zhí)行 test(undefined)
,不能解構(gòu) undefined
或 null
的屬性名時疫粥,您將會得到錯誤。因為在 undefined中沒有 name
屬性项秉。
If you don't mind using 3rd party libraries, there are a few ways to cut down null checking:
如果您不介意使用第三方庫慷彤,有一些方法可以減少 null 檢查:
- use Lodash get function
使用 Lodash 的 get 函數(shù)
- use Facebook open source's idx library (with Babeljs)
使用 Facebook 的開源庫 idx(以及 Babeljs)
Here is an example of using Lodash:
這是使用 Lodash 的例子:
// Include lodash library, you will get _
function test(fruit) {
console.log(__.get(fruit, 'name', 'unknown'); // get property name, if not available, assign default value 'unknown'
}
//test results
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
You may run the demo code here. Besides, if you are a fan of Functional Programming (FP), you may opt to use Lodash fp, the functional version of Lodash (method changed to get
or getOr
).
您可以在 這里 運行演示代碼底哗。此外跋选,如果你喜歡函數(shù)式編程(FP),你可以選擇使用 Lodash fp, 即 Lodash 的函數(shù)式版本(方法改為 get
或 getOr
)属划。
4候生、Favor Map / Object Literal than Switch Statement(選擇 Map 或?qū)ο笞置媪课ㄑ迹皇?Switch 語句)
Let's look at the example below, we want to print fruits based on color:
讓我們看看下面的例子,我們想要基于顏色打印水果名稱:
function test(color) {
// use switch case to find fruits in color
switch (color) {
case 'red':
return ['apple', 'strawberry'];
case 'yellow':
return ['banana', 'pineapple'];
case 'purple':
return ['grape', 'plum'];
default:
return [];
}
}
//test results
test(null); // []
test('yellow'); // ['banana', 'pineapple']
The above code seems nothing wrong, but I find it quite verbose. The same result can be achieve with object literal with cleaner syntax:
上面的代碼似乎沒有什么問題明肮,但我發(fā)現(xiàn)它相當冗長柿估。同樣的結(jié)果可以通過對象字面量和更簡潔的語法來實現(xiàn):
// use object literal to find fruits in color
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum']
};
function test(color) {
return fruitColor[color] || [];
}
Alternatively, you may use Map to achieve the same result:
或者陷猫,可以使用 Map 來實現(xiàn)相同的結(jié)果:
// use Map to find fruits in color
const fruitColor = new Map()
.set('red', ['apple', 'strawberry'])
.set('yellow', ['banana', 'pineapple'])
.set('purple', ['grape', 'plum']);
function test(color) {
return fruitColor.get(color) || [];
}
Map is the object type available since ES2015, allow you to store key value pair.
Map 是 ES2015 以后可用的對象類型绣檬,允許您存儲鍵值對。
Should we ban the usage of switch statement? Do not limit yourself to that. Personally, I use object literal whenever possible, but I wouldn't set hard rule to block that, use whichever make sense for your scenario.
我們應(yīng)該禁止使用 switch 語句嗎墨缘?不要把自己局限于此镊讼。就我個人而言,我盡可能地使用對象字面量卸亮,但是我不會設(shè)置嚴格的規(guī)則來阻止它嚼松,使用對您的場景有意義的任何一個。
Todd Motto has an article that dig deeper on switch statement vs object literal, you may read here.
Todd Motto 有一篇文章深入討論 switch 語句與對象字面量寝受,你可以在 這里 閱讀很澄。
TL;DR; Refactor the syntax(重構(gòu)的語法)
For the example above, we can actually refactor our code to achieve the same result with Array.filter
.
對于上面的示例颜及,我們實際上可以重構(gòu)代碼,以使用 Array.filter
獲得相同的結(jié)果俏站。
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) {
// use Array filter to find fruits in color
return fruits.filter(f => f.color == color);
}
There's always more than 1 way to achieve the same result. We have shown 4 with the same example. Coding is fun!
總有不止一種方法可以達到同樣的效果肄扎。我們展示了 4 個相同效果的例子。編碼是有趣的旭等!
5搔耕、Use Array.every & Array.some for All / Partial Criteria(所有或部分使用 Array.every & Array.some 的條件)
This last tip is more about utilizing new (but not so new) Javascript Array function to reduce the lines of code. Look at the code below, we want to check if all fruits are in red color:
最后一個技巧是關(guān)于使用新的(但不是很新)Javascript 數(shù)組函數(shù)來減少代碼行痰娱〔戮荆看看下面的代碼,我們想檢查所有的水果是否都是紅色的:
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
let isAllRed = true;
// condition: all fruits must be red
for (let f of fruits) {
if (!isAllRed) break;
isAllRed = (f.color == 'red');
}
console.log(isAllRed); // false
}
The code is so long! We can reduce the number of lines with Array.every
:
代碼太長了!我們可以用 Array.every
來減少行數(shù):
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
// condition: short way, all fruits must be red
const isAllRed = fruits.every(f => f.color == 'red');
console.log(isAllRed); // false
}
Much cleaner now right? In a similar way, if we want to test if any of the fruit is red, we can use Array.some
to achieve it in one line.
現(xiàn)在干凈多了拴念,對吧政鼠?類似地,如果我們想用一行代碼來判斷任何一個水果是否為紅色万搔,我們可以使用 Array.some
官帘。
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
// condition: if any fruit is red
const isAnyRed = fruits.some(f => f.color == 'red');
console.log(isAnyRed); // true
}
Summary
Let's produce more readable code together. I hope you learn something new in this article.
讓我們一起生成更多可讀的代碼刽虹。我希望你能從這篇文章中學(xué)到一些新的東西。
That's all. Happy coding!
這是所有胖缤。編碼快樂!