May 31, 2021 Article blog
1. Use Array.includes to handle multiple conditions
2. Write less nesting and return as early as possible
3. Use the function's default parameters and deconstruct
4. Map/Object may be a better choice than switch
5. Use Array.every and Array.some to handle all/partially met conditions
The article comes from the public number: front-ender
When using JavaScript, we often write a number of conditional statements. Here are five tips that let you write cleaner, prettier conditional statements.
Raise a chestnut :
// 条件语句
function test(fruit) {
if (fruit == 'apple' || fruit == 'strawberry') {
console.log('red');
}
}
At first glance, it doesn't seem like a big deal.
But what if we want to match more red fruits, say "cherry" and "cranberry"? D o we have to use more ||? to extend this statement?
We can use Array.includes to override the above conditional sentences.
function test(fruit) {
// 把条件提取到数组中
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (redFruits.includes(fruit)) {
console.log('red');
}
}
We extract red fruits (conditions) into an array, which makes our code look cleaner.
Let's add two conditions to the previous example:
If no fruit is provided, throw an error;
If the quantity of the fruit is greater than 10, print it out.
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// 条件 1:fruit 必须有值
if (fruit) {
// 条件 2:必须为红色
if (redFruits.includes(fruit)) {
console.log('red');
// 条件 3:必须是大量存在
if (quantity > 10) {
console.log('big quantity');
}
}
} else {
thrownewError('No fruit!');
}
}
// 测试结果
test(null); // 报错:No fruits
test('apple'); // 打印:red
test('apple', 20); // 打印:red,big quantity
Let's take a closer look at the code above, we have:
1
if/else
statement to filter invalid conditions;
Layer 3
if
statement nesting (conditions 1, 2 , 3).
Personally, one of the general rules I follow is to return as early as possible when invalid conditions are found.
/ Return as early as possible when an invalid condition is found /
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// 条件 1:尽早抛出错误
if (!fruit) thrownewError('No fruit!');
// 条件2:必须为红色
if (redFruits.includes(fruit)) {
console.log('red');
// 条件 3:必须是大量存在
if (quantity > 10) {
console.log('big quantity');
}
}
}
As a result, we write less nesting. This is a good code style, especially when the if statement is long (imagine that you have to scroll to the bottom to see if there is another else statement there, which is not a bit unpleasant).
If we reverse the condition, we can further reduce the nesting hierarchy. Watch out for the following Condition 2 statement to see how this works:
/ Return as early as possible when an invalid condition is found /
function test(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (!fruit) thrownewError('No fruit!'); // 条件 1:尽早抛出错误
if (!redFruits.includes(fruit)) return; // 条件 2:当 fruit 不是红色的时候,直接返回
console.log('red');
// 条件 3:必须是大量存在
if (quantity > 10) {
console.log('big quantity');
}
}
By reversing the condition of condition 2, our code is no longer nested.
This technique works well when the logical chain of our code is long and we want to stop executing the post-process when a condition is not met.
However, there are no hard rules that require you to do so. It's up to you, is this version of code (not nested) better and more readable to you than the previous version (condition 2 is nested)?
If it were me, I would choose the previous version (condition 2 is nested). The reasons are:
Such code is short and straightforward, and a nested if makes the structure clearer;
Conditional reversal leads to more thought processes (increased cognitive burden).
Therefore, always pursue less nesting and return earlier, but don't overdo it.
I guess you're probably
familiar with the following code, where we often need to check
null / undefined
and give default values:
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!
In fact, we can remove the variable q by the default parameter of the function.
function test(fruit, quantity = 1) { // 如果没有提供 quantity,默认为 1
if (!fruit) return;
console.log(`We have ${quantity}${fruit}!`);
}
//测试结果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!
Isn't it easier and more straightforward?
Note that all function parameters can have their default values.
For example, we can also give
fruit
a default value:
function test(fruit = ‘unknown’, quantity = 1)。
So what if
fruit
is an object?
Can we still use the default parameters?
function test(fruit) {
// 如果有值,则打印出来
if (fruit && fruit.name) {
console.log (fruit.name);
} else {
console.log('unknown');
}
}
//测试结果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
Looking at the example above, when the fruit name attribute exists, we want to print it out, otherwise we want to print "unknown".
We can avoid writing out the
fruit && fruit.name
by default parameters and deconstructing assignments.
Deconstructed - only the name property is obtained
The default parameter is an empty object.
function test({name} = {}) {
console.log (name || 'unknown');
}
//测试结果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
Now that we only need the
name
property of
fruit
we can deconstruct it
{name}
the
name
and then we can use the name variable in our code instead
fruit.name
We also use the default value of .
If we don't,
When you execute
test(undefined)
you get an error Cannot destructure property name of 'undefined' or 'null'.
Because there is no
name
property on
undefined
This is not very accurate, in fact, because deconstruction applies only to objects, not because there is no
name
property on
undefined
(not on empty objects).
Reference Deconstruction Assignment - MDN)
If you don't mind using third-party libraries, there are ways to help reduce null checks:
Use
Lodash get
function;
Use
Facebook
open source
idx
library (with Babeljs).
Here's an example of
Lodash
Use the method provided by the lodash library
function test(fruit) {
// 获取属性 name 的值,如果没有,设为默认值 unknown
console.log(_.get(fruit, 'name', 'unknown');
}
//测试结果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple
You can run the demo code here.
In addition, if you prefer functional programming (FP), you can choose to use
Lodash fp
the functional version of Lodash (the method name changes to get or getOr).
Let's look at the following example, we want to print out a variety of fruits according to color:
function test(color) {
// 使用 switch case 来找到对应颜色的水果
switch (color) {
case 'red':
return ['apple', 'strawberry'];
case 'yellow':
return ['banana', 'pineapple'];
case 'purple':
return ['grape', 'plum'];
default:
return [];
}
}
The test results
test(null); // []
test('yellow'); ['banana', 'pineapple']
The code above doesn't look wrong, but personally, it looks long. The same results can be achieved by object literally, and the syntax is more concise:
Use the literal amount of the object to find the fruit of the corresponding color
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum']
};
function test(color) {
return fruitColor[color] || [];
}
Alternatively, you can use Map to achieve the same effect:
Use Map to find the fruit of the corresponding color
const fruitColor = newMap()
.set('red', ['apple', 'strawberry'])
.set('yellow', ['banana', 'pineapple'])
.set('purple', ['grape', 'plum']);
function test(color) {
return fruitColor.get(color) || [];
}
Map is the new object type introduced in ES2015, allowing you to store key-value pairs.
Does that mean we should ban
switch
statements?
Don't limit yourself.
I'll use object literals myself whenever possible, but that's not to say I don't need
switch
depending on the scene.
In the example above, we can actually do the same by refactoring our code and using Array.filter.
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);
}
There is never more than one way to solve a problem. For this example we show four implementation methods.
Coding is fun!
The last tip is more about using new (and not very new) JavaScript array functions to reduce the number of lines of code.
Looking at the following code, we want to check if all the fruits are red:
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
}
This code is too long!
We can reduce the code through
Array.every
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
}
It's much clearer, isn't it?
Similarly, if we want to check if at least one fruit is red, we can use
Array.some
to do so in just one line of code.
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
}
Let's write more readable code together. I hope this article will bring you some help. That's it
That's what
W3Cschool编程狮
has to say
about 5 tips to get you to write better JavaScript,
and hopefully it'll help.