如何优雅的使用 if else

作为一个程序员在开发中 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'这一行都会打印。如果cond1true,则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语句可能导致复杂且难以维护的代码。相反,我们可以使用防御式编程使我们的代码更加可读和线性。我们可以将防御式编程应用于不同的情境,并将它们拆分为多个函数,以避免重复和分担职责。通过采用这种模式,我们最终编写更干净和更易维护的代码。

点赞收藏支持、手留余香、与有荣焉,动动你发财的小手哟,感谢各位大佬能留下您的足迹。

往期热门精彩推荐

面试相关热门推荐

前端万字面经------基础篇

前端万字面积------进阶篇

实战开发相关推荐

前端常用的几种加密方法

探索Web Worker在Web开发中的应用

不懂 seo 优化?一篇文章帮你了解如何去做 seo 优化

【实战篇】微信小程序开发指南和优化实践

前端性能优化实战

聊聊让人头疼的正则表达式

获取文件blob流地址实现下载功能

Vue 虚拟 DOM 搞不懂?这篇文章帮你彻底搞定虚拟 DOM

移动端相关推荐

移动端横竖屏适配与刘海适配

移动端常见问题汇总

聊一聊移动端适配

Git 相关推荐

通俗易懂的 Git 入门

git 实现自动推送

更多精彩详见:个人主页

相关推荐
栈老师不回家几秒前
Vue 计算属性和监听器
前端·javascript·vue.js
AskHarries5 分钟前
Java字节码增强库ByteBuddy
java·后端
前端啊龙6 分钟前
用vue3封装丶高仿element-plus里面的日期联级选择器,日期选择器
前端·javascript·vue.js
一颗松鼠10 分钟前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
佳佳_19 分钟前
Spring Boot 应用启动时打印配置类信息
spring boot·后端
小远yyds30 分钟前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
阿伟来咯~1 小时前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端1 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱1 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
许野平2 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono