如何优雅的使用 if else

作为一个程序员在开发中 if else 判断在代码中是必不可少的,但是 if else 判断使用多了嵌套多了不利于代码维护,看起来也头疼难以理解,接下来以为大家介绍一下我是怎么避免过多冗余的 if else 嵌套的。

0. 嵌套的if语句的典型用例

在最终执行有用操作之前,想对一些数据执行各种检查,以确保其有效性。这种情况下,可以使用if语句的嵌套来按顺序执行多个检查,只有当所有检查都通过时才执行有用的操作。这有助于确保数据在被处理之前是安全的。

冗余的写法:

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');  }  
}

优化后:

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中间件中看到了这种流程:

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();  
}

再看看这样的写法:

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语句。在这之后,如果不再进行更多的检查,我们可以执行我们一直想要执行的操作。

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 语句的后面。

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');  }  
}

2. 对每个嵌套的if执行相同的操作,直到达到成功的if

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...');
}

3. 插件提示

VS Code中安装JavaScript Booster扩展后,反转if语句变得非常容易。在这里,我们只需要将光标放在if关键字中,然后激活"显示代码操作"命令(默认情况下是Ctrl + .)。

4. 将代码拆分为多个函数,以始终避免使用else

如果我们在if/else中检查数据后还想执行其他操作怎么办?例如:

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检查之后的行:

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原则?

嗯,我们将逻辑分割成多个函数:

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中间件中:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/642533.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

StableDiffusion新版汉化

新旧版不同&#xff0c;这里以新版为例&#xff0c;用的是带链接&#xff0c;可以更新的方法。 步骤&#xff1a; 1.找到这个位置&#xff0c;依次点击&#xff0c;注意选项。 2.点击加载&#xff0c;等待刷新。 ctrlF搜索 zh_CN Localization 右边点击install&#xff0c…

外包干了4个月,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

Thin-LUN使用vdbench测试性能如何预埋数据

一、功能需求 Thin-LUN性能测试过程中&#xff0c;由于刚创建的THIN-LUN需要预埋数据&#xff0c;才能准确测试出实际性能&#xff0c;所以在第一次性能测试之前&#xff0c;需要使用vdbench预埋数据 二、组网图 无 三、配置步骤 seekpcteof 测试性能时&#xff0c;如果读…

GAMES101-Assignment8

一、总览 1.1 连接绳子的约束 在rope.cpp 中, 实现Rope 类的构造函数。这个构造函数应该可以创建一个 新的绳子(Rope) 对象&#xff0c;该对象从start 开始&#xff0c;end 结束&#xff0c;包含num_nodes 个节点。也就是如下图所示&#xff1a; 每个结点都有质量&#xff…

洛谷P3392 涂国旗-----暴力美学的演绎

# 涂国旗 ## 题目描述 某国法律规定&#xff0c;只要一个由 $N \times M$ 个小方块组成的旗帜符合如下规则&#xff0c;就是合法的国旗。&#xff08;毛熊&#xff1a;阿嚏——&#xff09; - 从最上方若干行&#xff08;至少一行&#xff09;的格子全部是白色的&#xff1b…

【论文阅读】Automated Runtime-Aware Scheduling for Multi-Tenant DNN Inference on GPU

该论文发布在 ICCAD’21 会议。该会议是EDA领域的顶级会议。 基本信息 AuthorHardwareProblemPerspectiveAlgorithm/StrategyImprovment/AchievementFuxun YuGPUResource under-utilization ContentionSW SchedulingOperator-level schedulingML-based scheduling auto-searc…

CGAL 网格连通聚类

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这里的思路其实与点云的欧式聚类非常类似,区别在于点云的欧式聚类是通过搜索半径对点云进行聚类,至于基于连通性网格面片聚类则是通过面片的邻近关系对面片进行聚类,大致的过程与欧式聚类是相同的: 首先,需要指…

Rustdesk 中VP8 / VP9 / AV1 是什么?

环境&#xff1a; Rustdesk1.1.9 VP8 / VP9 / AV1 问题描述&#xff1a; VP8 / VP9 / AV1 是什么&#xff1f; 解决方案&#xff1a; 1.VP8、VP9和AV1是视频编解码器&#xff0c;用于压缩和解压缩视频数据。它们是由Google和Alliance for Open Media&#xff08;AOM&#…

011 变量

变量的定义 注意事项 作用域 类变量&#xff1a;定义在类中的变量&#xff0c;类的整个生命周期内可用实例变量&#xff1a;定义在类中的变量&#xff0c;类的实例可以使用局部变量&#xff1a;定义在方法中的变量&#xff0c;仅在方法内可以使用 class Dog{// 类变量static …

Oracle 19c RAC集群管理 ---------关键参数以及常用命令

Oracle 19c RAC集群管理 ---------关键参数 Oracle 19C RAC 参数最佳实践 --开启强制归档 ALTER DATABASE FORCE LOGGING; --设置 30分钟 强制归档 ALTER SYSTEM SET ARCHIVE_LAG_TARGET1800 SCOPEBOTH SID*; --设置期望undo保持时间3h ALTER SYSTEM SET UNDO_RETENTION21600…

系统学习Python——警告信息的控制模块warnings:常用函数-[warnings.simplefilter]

分类目录&#xff1a;《系统学习Python》总目录 函数 warnings.simplefilter(action, categoryWarning, lineno0, appendFalse)在警告过滤器种类列表中插入一条简单数据项。函数参数的含义与filterwarnings()相同&#xff0c;但不需要正则表达式&#xff0c;因为插入的过滤器总…

机器学习 | 深入理解并掌握核心概念

在如今数字化时代的浪潮下&#xff0c;机器学习已经成为人工智能领域的璀璨明星。它像一面魔镜&#xff0c;赋予计算机系统学习和改进的能力&#xff0c;让机器能够从海量数据中提取规律、预测未来&#xff0c;甚至做出智能决策。本 专栏 将带您踏上机器学习的奇妙之旅&#xf…

题解:CF1920E. Counting Binary Strings

题解&#xff1a;CF1920E. Counting Binary Strings 题意简述 题目链接&#xff1a;Problem - E - Codeforces。 洛谷翻译&#xff1a;Counting Binary Strings - 洛谷。 思路解析 假设我们有一个01串str&#xff08;设里面有z个“1”&#xff09;&#xff0c;我们要求它里…

Ubuntu (Linux) 下创建软链接(即符号链接,相当于windows下的快捷方式)方法

Ubuntu (Linux) 下创建软链接&#xff08;即符号链接&#xff0c;相当于windows下的快捷方式&#xff09;方法 使用创建软链接的命令 #命令格式如下。注意&#xff1a;请使用绝对路径&#xff0c;否则链接可能失效 ln -s <源文件或目录的绝对路径> <符号链接文件&am…

ImportError: cannot import name ‘complete_to_chordal_graph‘解决

文章目录 ImportError: cannot import name complete_to_chordal_graph解决杂话问题解决注 ImportError: cannot import name complete_to_chordal_graph’解决 杂话 大伙儿应该都用过NetworkX这个库函数吧&#xff0c;是一个很方便的图相关的库&#xff0c;但是如果你的版本…

IDEA更改页面不重启

IDEA更改页面不重启 idea若依 修改包名 idea 1、修改IDEA设置 File -> Settings -> Build Execution Deployment -> Build Project automatically 勾选2、勾选Running Ctrl Shift Alt / 然后选择 Registry&#xff0c;勾上 Compiler.autoMake.allow.when.app.runn…

算法训练营第五十五天|392.判断子序列 115.不同的子序列

目录 Leetcode392.判断子序列Leetcode115.不同的子序列 Leetcode392.判断子序列 文章链接&#xff1a;代码随想录 题目链接&#xff1a;392.判断子序列 思路&#xff1a;正常动规记录&#xff0c;重点在于后面采用判断 class Solution { public:bool isSubsequence(string s, …

【MySQL进阶】视图_存储过程_存储函数_触发器

文章目录 视图基本介绍视图操作视图创建视图查询视图修改视图删除 存储过程基本介绍基本操作存储语法变量IF语句参数传递CASEWHILEREPEATLOOP游标 存储函数触发器基本介绍基本操作 总结 视图 基本介绍 视图概念&#xff1a;视图是一种虚拟存在的数据表&#xff0c;这个虚拟的表…

算法训练营第五十六天|583. 两个字符串的删除操作 72. 编辑距离

目录 Leetcode583. 两个字符串的删除操作Leetcode72. 编辑距离 Leetcode583. 两个字符串的删除操作 文章链接&#xff1a;代码随想录 题目链接&#xff1a;583. 两个字符串的删除操作 思路&#xff1a;直接记录需要改&#xff08;增或删&#xff09;几个&#xff0c;也就是求不…

seafile+onlyoffice集成部署

准备docker-compose version: "3" services:db:image: mariadb:10.11container_name: seafile-mysqlrestart: alwaysenvironment:- MYSQL_ROOT_PASSWORDsea123456 # Requested, set the roots password of MySQL service.- MYSQL_LOG_CONSOLEtruevolumes:- ./data/…