作为一个程序员在开发中 if else
判断在代码中是必不可少的,但是 if else
判断使用多了嵌套多了不利于代码维护,看起来也头疼难以理解,接下来以为大家介绍一下我是怎么避免过多冗余的 if else
嵌套的。
0. 嵌套的if语句的典型用例
在最终执行有用操作之前,想对一些数据执行各种检查,以确保其有效性。这种情况下,可以使用if语句的嵌套来按顺序执行多个检查,只有当所有检查都通过时才执行有用的操作。这有助于确保数据在被处理之前是安全的。
冗余的写法:
js
function sendMoney(account, amount) {
if (account.balance > amount) {
if (amount > 0) {
if (account.sender === 'user-token') {
account.balance -= amount;
console.log('Transfer completed');
} else {
console.log('Forbidden user');
}
} else {
console.log('Invalid transfer amount');
}
} else {
console.log('Insufficient funds');
}
}
优化后:
js
function sendMoney(account, amount) {
if (account.balance < amount) {
console.log('Insufficient funds');
return;
}
if (amount <= 0) {
console.log('Invalid transfer amount');
return;
}
if (account.sender !== 'user-token') {
console.log('Forbidden user');
return;
}
account.balance -= amount;
console.log('Transfer completed');
}
与嵌套的if语句不同,我们有多个if语句,每个if语句执行检查并在条件不满足时立即返回。在这种模式中,我们可以将每个if语句称为防御式编程(guard clause)。这种方式使代码更易阅读和维护,减少了嵌套深度。
如果有使用 node.js 的童鞋,可能会在Express中间件中看到了这种流程:
js
function authMiddleware(req, res, next) {
const authToken = req.headers.authorization;
if (!authToken) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (authToken !== 'secret-token') {
return res.status(401).json({ error: 'Invalid token' });
}
if (req.query.admin === 'true') {
req.isAdmin = true;
}
next();
}
再看看这样的写法:
js
function authMiddleware(req, res, next) => {
const authToken = req.headers.authorization;
if (authToken) {
if (authToken === 'secret-token') {
if (req.query.admin === 'true') {
req.isAdmin = true;
}
return next();
} else {
return res.status(401).json({ error: 'Invalid token' });
}
} else {
return res.status(401).json({ error: 'Unauthorized' });
}
};
是不是瞬间感觉这样的代码就比较恶心了,所以我们尽量要避免回调地狱的写法,采用防御式编程的写法,这种模式使代码更加清晰和易于维护。
1. 如何去写防御式编程
0. 找到最内层/成功的 if 语句
在这里,我们可以清楚地看到它是cond3
的if语句。在这之后,如果不再进行更多的检查,我们可以执行我们一直想要执行的操作。
js
function func(cond1, cond2, cond3) {
if (cond1) {
if (cond2) {
if (cond3) {
console.log('PASSED!');
console.log('taking success action...');
} else {
console.log('failed condition 3');
}
} else {
console.log('failed condition 2');
}
} else {
console.log('failed condition 1');
}
}
1.将最外层的 if 语句 return
否定 if
条件以将 else
语句的主体放入其中,并在其后添加一个 return
语句。
删除 else
语句的大括号(保留主体,因为它仍然包含以前嵌套的if语句),并将 if
语句的右括号移到 return
语句的后面。
js
function func(cond1, cond2, cond3) {
if (!cond1) { // 👈 反转后的if条件
// 👇 以前的else子句的主体
console.log('failed condition 1');
return; // 👈 失败时退出
}
// 👇 需要转换的剩余嵌套if语句
if (cond2) {
if (cond3) {
console.log('PASSED!');
console.log('taking success action...');
} else {
console.log('failed condition 3');
}
} else {
console.log('failed condition 2');
}
}
02.对每个嵌套的if执行相同的操作,直到达到成功的if
js
function func(cond1, cond2, cond3) {
if (!cond1) {
console.log('failed condition 1');
return;
}
if (!cond2) {
console.log('failed condition 2');
return;
}
if (!cond3) {
console.log('failed condition 3');
return;
}
console.log('PASSED!');
console.log('taking success action...');
}
03. 插件提示
在VS Code
中安装JavaScript Booster
扩展后,反转if语句变得非常容易。
在这里,我们只需要将光标放在if关键字中,然后激活"显示代码操作"命令(默认情况下是Ctrl + .)。
04. 将代码拆分为多个函数,以始终避免使用else
如果我们在if/else中检查数据后还想执行其他操作怎么办?例如:
js
function func(cond1, cond2) {
if (cond1) {
if (cond2) {
console.log('PASSED!');
console.log('taking success action...');
} else {
console.log('failed condition 2');
}
console.log('after cond2 check');
} else {
console.log('failed condition 1');
}
console.log('after cond1 check');
}
在这个函数中,无论cond1
的值如何,'after cond1 check'这一行都会打印。如果cond1
为true
,则cond2
的值也是类似的情况。
在这种情况下,要使用防御使编程需要更多的工作:
如果我们尝试使用防御使编程,将会重复出现在if/else
检查之后的行:
js
function func(cond1, cond2) {
if (!cond1) {
console.log('failed condition 1');
console.log('after cond1 check');
return;
}
if (!cond2) {
console.log('failed condition 2');
console.log('after cond2 check');
console.log('after cond1 check');
return;
}
console.log('PASSED!');
console.log('taking success action...');
console.log('after cond2 check');
console.log('after cond1 check');
}
func(true);
由于这些行必须被打印,我们在返回之前在防护子句中打印它们。然后,我们在所有(!)后续的防护子句中再次打印它们。如果所有的防护子句都通过,那么在主函数体中再次打印。
那么,我们该怎么办?如何使用防御式编程并仍然遵守DRY原则?
嗯,我们将逻辑分割成多个函数:
js
function func(cond1, cond2) {
checkCond1(cond1, cond2);
console.log('after cond1 check');
}
function checkCond1(cond1, cond2) {
if (!cond1) {
console.log('failed condition 1');
return;
}
checkCond2(cond2);
console.log('after cond2 check');
}
function checkCond2(cond2) {
if (!cond2) {
console.log('failed condition 2');
return;
}
console.log('PASSED!');
console.log('taking success action...');
}
让我们将这个方法应用到之前看到的Express中间件中:
js
function authMiddleware(req, res, next) {
checkAuthValidTokenAdmin(req, res, next);
}
function checkAuthValidTokenAdmin(req, res, next) {
const authToken = req.headers.authorization;
if (!authToken) {
return res.status(401).json({ error: 'Unauthorized' });
}
checkValidTokenAdmin(req, res, next);
}
function checkValidTokenAdmin(req, res, next) {
const authToken = req.headers.authorization;
if (authToken !== 'secret-token') {
return res.status(401).json({ error: 'Invalid token' });
}
checkAdmin(req, res, next);
}
function checkAdmin(req, res, next) {
if (req.query.admin === 'true') {
req.isAdmin = true;
}
next();
}
在某种程度上,我们用责任链模式替代了if/else
语句。当然,对于像基本的Express
请求中间件这样的简单逻辑,这可能有些过度,但这里的优点在于它将每个额外的检查委托给一个单独的函数,分离了职责,防止了过多的嵌套。
主要收获 在代码中使用嵌套的if
语句可能导致复杂且难以维护的代码。相反,我们可以使用防御式编程使我们的代码更加可读和线性。我们可以将防御式编程应用于不同的情境,并将它们拆分为多个函数,以避免重复和分担职责。通过采用这种模式,我们最终编写更干净和更易维护的代码。
点赞收藏支持、手留余香、与有荣焉,动动你发财的小手哟,感谢各位大佬能留下您的足迹。
往期热门精彩推荐
面试相关热门推荐
实战开发相关推荐
移动端相关推荐
Git 相关推荐
更多精彩详见:个人主页