Jun 01, 2021 Article blog
1. Nested hierarchy optimization
2. Optimal processing of multi-conditional branches
3. Simplify logical judgment with the new features of the array
5. Determines whether all items in the array meet a condition
6. Determine if there is an item in the array that meets the criteria
7. The default value of the function
9. Use deconstruction with default parameters
10.. Complex data deconstruction
If you want to be a qualified programmer, code optimization is a very important part of a high-quality piece of code that makes it easy for people to see, both for themselves and for others.
if else
switch case
is the most common conditional judgment statement in everyday development, this seemingly simple statement, when encountered in a complex business scenario, if not handled well, there will be a lot of logical nesting, poor readability and difficult to scale.
To write high-quality, maintainable code, let's start with the smallest and see where logical judgments can be optimized during front-end development.
Here are some optimization tips from
JavaScript
syntax and
React JSX
syntax.
function supply(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
// 条件 1: 水果存在
if(fruit) {
// 条件 2: 属于红色水果
if(redFruits.includes(fruit)) {
console.log('红色水果');
// 条件 3: 水果数量大于 10 个
if (quantity > 10) {
console.log('数量大于 10 个');
}
}
} else {
throw new Error('没有水果啦!');
}
}
Analysis of the above conditions to judge that there are three layers
if
condition nesting.
If
return
invalid condition is dropped in advance, it is easier to understand and maintain
if else
multi-nested hierarchy is reduced to one level.
function supply(fruit, quantity) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if(!fruit) throw new Error('没有水果啦'); // 条件 1: 当 fruit 无效时,提前处理错误
if(!redFruits.includes(fruit)) return; // 条件 2: 当不是红色水果时,提前 return
console.log('红色水果');
// 条件 3: 水果数量大于 10 个
if (quantity > 10) {
console.log('数量大于 10 个');
}
}
When you need to enumerate values to handle different business branch logic, the first reaction is to write down
if else
Let's take a look at:
function pick(color) {
// 根据颜色选择水果
if(color === 'red') {
return ['apple', 'strawberry'];
} else if (color === 'yellow') {
return ['banana', 'pineapple'];
} else if (color === 'purple') {
return ['grape', 'plum'];
} else {
return [];
}
}
In the implementation above:
if else
too many if else branches
if else
better suited for conditional interval judgment, while
switch case
is more suitable for branch judgment for specific enumerated values
After optimizing the above code with
switch case
function pick(color) {
// 根据颜色选择水果
switch (color) {
case 'red':
return ['apple', 'strawberry'];
case 'yellow':
return ['banana', 'pineapple'];
case 'purple':
return ['grape', 'plum'];
default:
return [];
}
}
switch case
case-optimized code looks neatly organized and clear-minded, but it's still lengthy.
Continue to optimize:
Object
{ key: value }
structure, we can enumerate all cases in
Object
and then use
key
as an index to get content directly from
Object.key
or
Object[key]
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum'],
}
function pick(color) {
return fruitColor[color] || [];
}
Map
data structures, real
key
value
key values are paired to structures;
const fruitColor = new Map()
.set('red', ['apple', 'strawberry'])
.set('yellow', ['banana', 'pineapple'])
.set('purple', ['grape', 'plum']);
function pick(color) {
return fruitColor.get(color) || [];
}
Once optimized, the code is simpler and easier to extend.
For better readability, you can also define objects in a more semantic way, and then use
Array.filter
to achieve the same effect.
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 pick(color) {
return fruits.filter(f => f.color == color);
}
(Recommended tutorial: JavaScript tutorial)
Clever use of the new features of the array provided in
ES6
also makes it easier for us to handle logical judgments.
When coding encounters multiple judgmental conditions, instinctively write down the following code (in fact, it is also the process-oriented coding that best expresses business logic).
function judge(fruit) {
if (fruit === 'apple' || fruit === 'strawberry' || fruit === 'cherry' || fruit === 'cranberries' ) {
console.log('red');
}
}
But when
type
is coming up to 10 or more, can we just continue to add
||
to maintain the code?
Try Array.includes
// 将判断条件抽取成一个数组
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
function judge(type) {
if (redFruits.includes(fruit)) {
console.log('red');
}
}
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function match() {
let isAllRed = true;
// 判断条件:所有的水果都必须是红色
for (let f of fruits) {
if (!isAllRed) break;
isAllRed = (f.color === 'red');
}
console.log(isAllRed); // false
}
In the above implementation, all items in the array are qualified primarily for processing.
Using
Array.every
allows you to implement this logic with ease:
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function match() {
// 条件:所有水果都必须是红色
const isAllRed = fruits.every(f => f.color == 'red');
console.log(isAllRed); // false
}
Array.some
which handles scenarios primarily to determine whether there is a condition in the array that meets the criteria.
If you want to know if you have red fruit, you can use
Array.some
method directly:
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
// 条件:是否有红色水果
const isAnyRed = fruits.some(f => f.color == 'red');
There are many other new features of
Array.find
Array.slice
Array.findIndex
Array.reduce
Array.splice
and so on, that you can choose to use in a real-world scenario.
const buyFruit = (fruit,amount) => {
if(!fruit){
return
}
amount = amount || 1;
console.log(amount)
}
We often need to deal with some parameter defaults inside the function, the above code is no stranger to everyone, using the default parameters of the function, can be very good to help deal with this scenario.
const buyFruit = (fruit,amount = 1) => {
if(!fruit){
return
}
console.log(amount,'amount')
}
We can see how the default parameters are implemented through
Babel
translation.
From the translation results above, it can be found that the default parameters are used only if the parameter is
undefined
The results of the test are as follows:
buyFruit('apple',''); // amount
buyFruit('apple',null); //null amount
buyFruit('apple'); //1 amount
So with the default parameter, we need to be aware that the default parameter
amount=1
not the same as the amount
amount || 1
When function arguments are objects, we can simplify the logic by deconstructing them with default parameters.
Before:
const buyFruit = (fruit,amount) => {
fruit = fruit || {};
if(!fruit.name || !fruit.price){
return;
}
...
amount = amount || 1;
console.log(amount)
}
After:
const buyFruit = ({ name,price }={},amount) => {
if(!name || !prices){
return;
}
console.log(amount)
}
Deconstruction works well with default parameters when working with simpler objects, but in some complex scenarios we may be faced with more complex structures.
const oneComplexObj = {
firstLevel:{
secondLevel:[{
name:"",
price:""
}]
}
}
This time, if you deconstruct to get the value in the object.
const {
firstLevel:{
secondLevel:[{name,price]=[]
}={}
} = oneComplexObj;
Readability can be poor, and the default values for multi-layer deconstruction and data anomalies need to be considered.
In this case, if you use
lodash
library in your project, you can use the
lodash/get
method in it.
import lodashGet from 'lodash/get';
const { name,price} = lodashGet(oneComplexObj,'firstLevel.secondLevel[0]',{});
Policy patterns: Define a series of algorithms, encapsulate them one by one, and replace them with each other.
Use scenario: Policy patterns are object behavior patterns that can be used when encountering instance objects with the same behavior interface and different logical implementations within the behavior, or policy patterns when a group of objects can dynamically select one of several behaviors as needed, as an example of the second:
Before:
const TYPE = {
JUICE:'juice',
SALAD:'salad',
JAM:'jam'
}
function enjoy({type = TYPE.JUICE,fruits}){
if(!fruits || !fruits.length) {
console.log('请先采购水果!');
return;
}
if(type === TYPE.JUICE) {
console.log('榨果汁中...');
return '果汁';
}
if(type === TYPE.SALAD) {
console.log('做沙拉中...');
return '拉沙';
}
if(type === TYPE.JAM) {
console.log('做果酱中...');
return '果酱';
}
return;
}
enjoy({type:'juice',fruits});
Use ideas: Define policy objects to encapsulate different behaviors, provide policy selection interfaces, and invoke corresponding behaviors when different rules occur.
After:
const TYPE = {
JUICE:'juice',
SALAD:'salad',
JAM:'jam'
}
const strategies = {
[TYPE.JUICE]: function(fruits){
console.log('榨果汁中...');
return '果汁';
},
[TYPE.SALAD]:function(fruits){
console.log('做沙拉中...');
return '沙拉';
},
[TYPE.JAM]:function(fruits){
console.log('做果酱中...');
return '果酱';
},
}
function enjoy({type = TYPE.JUICE,fruits}) {
if(!type) {
console.log('请直接享用!');
return;
}
if(!fruits || !fruits.length) {
console.log('请先采购水果!');
return;
}
return strategies[type](fruits);
}
enjoy({type:'juice',fruits});
(Recommended micro-class: JavaScript micro-course)
JSX
is a
JavaScript
syntax extension that looks like
XML
JSX
is typically used in
React
to describe interface information, and
ReactDOM.render()
JSX
interface information to the page.
JavaScript
expressions are supported in
JSX
and it is common to loop through output subcompletes, trot expression judgments, and more complex direct abstractions of a function.
With so many
JavaScript
expressions written in
JSX
the overall code looks a bit cluttered.
Try to optimize it!
JSX-Control-Statements
is a
Babel
plug-in that extends
JSX
ability to handle conditional judgment and looping as labels.
<If>
label content is rendered only when
condition
is
true
which is equivalent to the simplest troy expression.
Before:
{ condition() ? 'Hello World!' : null }
After:
<If condition={ condition() }>Hello World!</If>
Note:
<Else />
has been discarded and complex conditions can be determined
<Choose>
tags.
< Include At Least One
<When>
> Label, Optional <
<Otherwise>
> Label Under The
<Choose>
> Label.
<When>
label content is rendered only when
condition
is
true
which is equivalent to an
if
conditional judgment branch.
<Otherwise>
label is equivalent to the last
else
branch.
Before:
{ test1 ? <span>IfBlock1</span> : test2 ? <span>IfBlock2</span> : <span>ElseBlock</span> }
After:
<Choose>
<When condition={ test1 }>
<span>IfBlock1</span>
</When>
<When condition={ test2 }>
<span>IfBlock2</span>
</When>
<Otherwise>
<span>ElseBlock</span>
</Otherwise>
</Choose>
<For>
label needs to declare
of
each
attribute.
of
receives objects that can be accessed using iterators.
each
represents the current pointing element at the time of iterator access.
Before:
{
(this.props.items || []).map(item => {
return <span key={ item.id }>{ item.title }</span>
})
}
After:
<For each="item" of={ this.props.items }>
<span key={ item.id }>{ item.title }</span>
</For>
Note:
<For>
label cannot be used as a root element.
<With>
labels provide the ability to pass variable parameters.
Before:
renderFoo = (foo) => {
return <span>{ foo }</span>;
}
// JSX 中表达式调用
{
this.renderFoo(47)
}
After:
<With foo={ 47 }>
<span>{ foo }</span>
</With>
Using these label optimization codes can reduce the explicit
JavaScript
expressions that exist in
JSX
and make our code look cleaner, but the ability of these label encapsulations needs to be converted to equivalent
JavaScript
expressions at compile time.
These are some common summaries of logical judgment optimization techniques. Of course, writing high-quality, maintainable code, in addition to logical judgment optimization, but also need to have clear comments, well-meaning variable naming, reasonable code structure splitting, logical layering and decoupling, and a higher level of logical abstraction of the appropriate business, and so on, I believe you also have some of their own experience in this regard.