之前在写一个 React 项目时,我发现我用了太多的 if else,于是在重构代码的时候,我尝试删除了大量的 if else,最终发现代码变简洁了,可读性更高了。所以如果你的代码中也出现了大量的if else,说明你的代码出问题了。
在 code reviews 的时候,我会关注下面几个问题:
- 一个函数干了几件事情,是否需要分离,让一个函数只干一件事?
- 检查函数中的
if else,看是否可以替换它。 - 怎么改善可读性?比如用设计模式替换
if else(我最喜欢用对象映射模式)。 - 如果必须使用
if else,那么删除else,保留if,并返回默认值。
接下来我会举几个例子来展示如何替代 if else。
删除 else
重构前:
if (red) {
return false;
} else if (blue) {
return false;
} else {
return true;
}
重构后:
if (red || blue) {
return false;
}
return true;
重构后的代码可以很直观的看到默认返回值,更简洁易读。
组合函数
当你发现一个函数做了很多件事情,那么用组合函数可以很好的处理它。把函数分离成多个函数,然后把它们组合起来。
举个例子:我们来创建一个可以生成包含皮毛和爪子的雌性动物的函数
import { flow } from 'lodash';
const femaleAnimalsWithFurAndClaws = flow(
getFemales,
getAnimalsWithFur,
getAnimalsWithClaws,
)(animals);
代码处理成这样,我们可以很轻松的重用里面的函数(比如 getFemales)。
对象映射模式
这是我最喜欢的设计模式之一,可使用的场景也很多,不管是在前端还是后端编码中都可以用。它带来的好处就是,让代码简洁易读。每次我用这种设计模式的时候,我都觉得我的代码不是代码,而是说明书(^_^)。
来看一个简单的例子:
const colors = {
red: false,
blue: false,
'default': true,
};
const colorMapper = color => colors[color] || colors['default'];
const color = colorMapper(item.color);
它由两个部分组成,一个储存返回结果的对象和一个映射函数。
我们设置了默认值,即使在调用 colorMapper 函数的时候,没有传入参数,或者传入了错误参数,都不会报错,并返回默认值。后期维护的时候,我们也可以很轻松的新增其他的颜色。
当然我们也可以用 switch 来达到同样的效果,就我个人而言并不喜欢这种语法,还是对象映射的方式更简洁优美(^_^)。
对象映射模式 + React
用 React 写项目,才是对象映射模式大放异彩的时候。当我们渲染很多不同的组件时,我们需要在代码中写大量的条件判断。如果用对象映射模式,问题就变得简单了。看下面的例子:
首先数据看起来是这样的,每个对象都有一个 type 和 content 键。
const items = [{
type: ‘hero’,
content: : {…},
}, {
type: 'text',
content: : {…},
}, {
type: 'image_and_text',
content: : {…},
}, {
type: 'text',
content: : {…},
}, {
type: 'call_to_action',
content: : {…},
}];
然后写一个映射函数,每个键表示一个 React 组件,每个组件都有 prop,就上面数据中的 content。
const components = {
hero: HeroComponent,
text: TextComponent,
image_and_text: ImageAndTextComponent,
call_to_action: CallToActionComponent,
'default': null,
};
const componentMapper = type =>
components[type] || components['default'];
接下来就可以在项目中用了:
import react from ‘react’;
const RenderItems = props => {
const componentList = props.items((item, index) => {
const Component = componentMapper(item.type);
return <Component content={item.content} />
};
return (
<div>
{componentList}
</div>
)
};