因此,我们在日常编码时,有必要采取一些措施避免这些问题。本文的初衷不是建议大家完全不用if-else,而是希望我们能够在学会更多解决方案后更优雅地编码。
二、8种if-else的优化/替代方案
1. 使用排非策略:!、!!
逻辑非(logic NOT),是逻辑运算中的一种,就是指本来值的反值。
当你想这么写时……
1、判断是否为空
if(value === null || value === NaN || value === 0 || value === ''|| value === undefined )
{
……
}
2、判断是否数组是否含有符合某条件的元素
const name = arr.find(item => item.status === 'error')?.name;
if(name !== undefined && name !== ''){
……
}
复制代码
不妨尝试这么写:
1、判断是否为空
if(!value){……}
2、判断是否数组是否含有符合某条件的元素
if(!!arr.find(item => item.status === 'error')?.name){……}
复制代码
2. 使用条件(三元)运算符: c ? t : f
三元运算符: condition ? exprIfTrue : exprIfFalse; 如果条件为真值,则执行冒号(:)前的表达式;若条件为假值,则执行最后的表达式。
当你想这么写时……
let beverage = '';
if(age > 20){
beverage = 'beer';
} else {
beverage = 'juice';
}
复制代码
不妨尝试这么写:
const beverage = age > 20 ? 'beer' : 'juice';
复制代码
tips: 建议只用一层三元运算符,多层嵌套可读性差。
3. 使用短路运算符:&&、 ||
-
&& 为取假运算,从左到右依次判断,如果遇到一个假值,就返回假值,以后不再执行,否则返回最后一个真值;
-
|| 为取真运算,从左到右依次判断,如果遇到一个真值,就返回真值,以后不再执行,否则返回最后一个假值。
当你想这么写时……
if (isOnline){
makeReservation(user);
}
复制代码
不妨尝试这么写:
isOnline && makeReservation(user);
复制代码
4. 使用 switch 语句
当你想这么写时……
let result;
if (type === 'add'){
result = a + b;
} elseif(type === 'subtract'){
result = a - b;
} elseif(type === 'multiply'){
result = a * b;
} elseif(type === 'divide'){
result = a / b;
} else {
console.log('Calculation is not recognized');
}
复制代码
不妨尝试这么写:
let result;
switch (type) {
case'add':
result = a + b;
break;
case'subtract':
result = a - b;
break;
case'multiply':
result = a * b;
break;
case'divide':
result = a / b;
break;
default:
console.log('Calculation is not recognized');
}
复制代码
个人认为,对于这类比较简单的判断,用switch语句虽然不会减少代码量,但是会更清晰喔。
5. 定义相关函数拆分逻辑,简化代码
当你想这么写时……
functionitemDropped(item, location) {
if (!item) {
returnfalse;
} elseif (outOfBounds(location) {
var error = outOfBounds;
server.notify(item, error);
items.resetAll();
returnfalse;
} else {
animateCanvas();
server.notify(item, location);
returntrue;
}
}
复制代码
不妨尝试这么写:
// 定义dropOut和dropIn, 拆分逻辑并提高代码可读性functionitemDropped(item, location) {
const dropOut = function () {
server.notify(item, outOfBounds);
items.resetAll();
returnfalse;
};
const dropIn = function () {
animateCanvas();
server.notify(item, location);
returntrue;
};
return !!item && (outOfBounds(location) ? dropOut() : dropIn());
}
复制代码
细心的朋友会发现,在这个例子中,同时使用了前文提及的优化方案。这说明我们在编码时可以根据实际情况混合使用多种解决方案。
6. 将函数定义为对象,通过穷举查找对应的处理方法
- ① 定义普通对象
对于方案3的例子,不妨尝试这么写:
functioncalculate(action, num1, num2) {
const actions = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b,
divide: (a, b) => a / b,
};
return actions[action]?.(num1, num2) ?? "Calculation is not recognized";
}
复制代码
- ② 定义 Map 对象
普通对象的键需要是字符串,而 Map 对象的键可以是一个对象、数组或者更多类型,更加灵活。
let statusMap = newMap([
[
{ role: "打工人", status: "1" },
() => { /*一些操作*/},
],
[
{ role: "打工人", status: "2" },
() => { /*一些操作*/},
],
[
{ role: "老板娘", status: "1" },
() => { /*一些操作*/},
],
]);
let getStatus = function (role, status) {
statusMap.forEach((value, key) => {
if (JSON.stringify(key) === JSON.stringify({ role, status })) {
value();
}
});
};
getStatus("打工人", "1"); // 一些操作复制代码
tips: JSON.stringify()可用于深比较/深拷贝。
7. 使用责任链模式
责任链模式:将整个处理的逻辑改写成一条责任传递链,请求在这条链上传递,直到有一个对象处理这个请求。
例如 JS 中的事件冒泡。
简单来说,事件冒泡就是在一个对象上绑定事件,如果定义了事件的处理程序,就会调用处理程序。相反没有定义的话,这个事件会向对象的父级传播,直到事件被执行,最后到达最外层,document对象上。