开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情
出来工作几年,相信大家都会看到过几次经手的屎山项目,里面夹杂着非常多的业务逻辑代码。
表面上说是可以锻炼思维,提升业务能力,其实就是对着一堆if else语句来擦屁股,有时候debugger排查分分钟让我们怀疑人生,不,我不能做只会使用if else 做CURD操作的工具人,我们要使用一些高级语法来优雅地写代码。
那么都有哪些coding方式可以完美取代if else?
二元运算符
在函数定义中,有没有更加优雅的coding手法?有,我们可以使用||运算符来实现,如下:
function fn(a){
if(!a){
a = 'test'
}
}
// 使用 || 运算符来实现
function fn(name){
name = name || 'test'
}
三元运算符
没错,我第一个想到的就是三元运算符,也是我日常工作中最常使用的减少代码量的方法。
在这里我只推荐一层三元表达式,因为多层嵌套的三元表达式运算符不具备很良好的可读性(格式化会发现跟回调地狱差不多)
const fn = (isTure) => {
if (isTure) {
return 1
} else {
return 0
}
}
// 使用三元运算符
const fn = (isTrue) => {
return isTrue ? 1 : 0
}
三元运算符的使用场景还很多,比如:条件赋值,递归...
// num值在nBoolean为true时为0,否则为5
let num = nBoolean ? 10 : 5
// 求0-n之间整数的和
let sum = 0
function add(n) {
sum += n
return n >= 2 ? add(n - 1) : sum
}
let numb = add(10) //55
这么一对比,是不是代码要简洁很多有木有!?
switch case
三元运算符虽然能够让代码更加简洁,但是缺点是只能处理简单的判断,超过3个以上的判断,个人是不推荐再使用三元运算符,因为看着脑壳痛,写着也累,看着也累。
这时候我就推荐使用switch case!
switch case的优点是可读性比较高,对于多重判断,可以使用switch case。
举个栗子:
有A,B,C,D四种类型,在A,B输出1,C输出2,D输出3,默认输出0。
let type = 'A'
// if else if
if (type === 'A' || type === 'B') {
console.log(1)
} else if (type === 'C') {
console.log(2)
} else if (type === 'D') {
console.log(3)
} else {
console.log(0)
}
目前看起来还行,但是一旦业务量一多,那也是妥妥的回调地狱!
// switch case
switch (type) {
case 'A':
case 'B':
console.log(1)
break
case 'C':
console.log(2)
break
case 'D':
console.log(3)
break
default:
console.log(0)
}
对象配置
如果条件超过三种,else if 写起来不太优雅,switch case代码行数也差不多,就像下面的代码
function formatData(a) {
let c = ''
if (a === 1) {
c = '汉族'
} else if (a === 2) {
c = '苗族'
} else if (a === 3) {
c = '维吾尔族'
} else if (a === 4) {
c = '回族'
} else if (a === 5) {
c = '藏族'
}
// ... 等等等等
return c
}
const result = formatData(2) // 对应的苗族
这个要是有64个名族,那我们要写64个else if 啊 ~~,着实有点可怕,那么有没有好的方法呢,看下面代码:
const obj = {
1: "汉族",
2: "苗族",
3: "维吾尔族",
4: "回族",
5: "藏族",
// ...等等等等
};
function formatData(a) {
return obj[a]
}
const result = formatData(2); // 苗族
上面的代码直接省去64个 else if, 有点小兴奋。
有时候我在实际开发遇到过这样一个情景,我需要根据用户不同的操作类型对同一份数据进行不同加工,比如新增,修改,删除等。那么我用 else if 是这么做的:
function del() {} // 删除操作
function add() {} // 新增
function update() {} // 更新
function process(operateType) {
if (operateType === 'del') {
del()
} else if (operateType === 'add') {
add()
} else if (operateType === 'update') {
update()
}
}
process('del') // 删除
当然我们也可以使用 ES6 的 map 数据结构,像这样:
let typeFn = new Map([
['del_1', function () {/*do something*/ }],
['add_2', function () {/*do something*/ }],
['update_3', function () {/*do something*/ }],
]);
function process(operateType, status) {
typeFn.get(`${operateType}_${status}`)();
};
process('del', 1); // 删除
数组配置
在处理条件判断时,我们常会遇到条件与对应结果全部已知的情况,比如我们要根据用户的经验设置等级头衔,[0,100)–萌新,[100,200)–骑士,[200,300)–英雄,[300-无限大]–黄金圣斗士,那么用else if怎么写已经没有悬念了:
function getHero(experience) {
if (experience < 100) {
return '萌新'
} else if (experience < 200 && experience >= 100) {
return '骑士'
} else if (experience < 300 && experience >= 200) {
return '英雄'
} else if (experience >= 300) {
return '黄金圣斗士'
}
}
const level = getHero(351) //黄金圣斗士
对于这种条件与结果已知的情况,我们其实可以通过数组配置的形式将条件结果抽离出来,像这样:
function getHero(param) {
let experience = [300, 200, 100]
let level = ['黄金圣斗士', '英雄', '骑士', '萌新']
for (let i = 0; i < experience.length; i++) {
if (param >= experience[i]) {
return level[i]
}
}
return level[level.length - 1]
}
const level = getHero(250) //英雄
这么做的好处就是便于管理条件与执行结果,如果后面新增了等级判断,我们不用去修改业务逻辑中的 else if 语句长度,只用单纯维护我们抽离的数据即可。
还有一个大杀器:
对象配置/策略模式
策略模式就是将一系列算法封装起来,并使它们相互之间可以替换。被封装起来的算法具有独立性,外部不可改变其特性。
接下来我们用对象配置的方法实现一下上述的例子:
let type = 'A'
let data = {
'A': 1,
'B': 1,
'C': 2,
'D': 3,
default: 0
}
console.log(data[type]) // 1
根据不同的用户使用不同的折扣,如:普通用户不打折,普通会员用户9折,年费会员8.5折,超级会员8折。
使用对象配置/策略模式实现:
// 获取折扣 -- 使用对象配置/策略模式
const getDiscount = (userKey) => {
// 我们可以根据用户类型来生成我们的折扣对象
let discounts = {
'普通会员': 0.9,
'年费会员': 0.85,
'超级会员': 0.8,
'default': 1
}
return discounts[userKey] || discounts['default']
}
console.log(getDiscount('普通会员')) // 0.9
看着如此简洁的代码,是不是内心有一股幸福感油然而生!
总结
以上,我们大致介绍了6种可取代 if else 的方式,具体还是要看业务需求哦 ~