【面试题】如何避免使用过多的 if else?

news2024/11/14 12:17:52

大厂面试题分享 面试题库

前后端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库

一、引言

相信大家听说过回调地狱——回调函数层层嵌套,极大降低代码可读性。其实,if-else层层嵌套,如下图所示,也会形成类似回调地狱的情况。

当业务比较复杂,判断条件比较多,项目进度比较赶时,特别容易使用过多if-else。其弊端挺多的,如代码可读性差、代码混乱、复杂度高、影响开发效率、维护成本高等。

因此,我们在日常编码时,有必要采取一些措施避免这些问题。本文的初衷不是建议大家完全不用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对象上。

这意味着,在这种模式下,总会有程序处理该事件。

再举个🌰,当你想这么写时……

functiondemo (a, b, c) {
  if (f(a, b, c)) {
    if (g(a, b, c)) {
      // ...
    }
    // ...elseif (h(a, b, c)) {
      // ...
    }
    // ...
  } elseif (j(a, b, c)) {
    // ...
  } elseif (k(a, b, c)) {
    // ...
  }
}
复制代码

不妨参考这种写法:

const rules = [
  {
    match: function (a, b, c) { /* ... */ },
    action: function (a, b, c) { /* ... */ }
  },
  {
    match: function (a, b, c) { /* ... */ },
    action: function (a, b, c) { /* ... */ }
  },
  {
    match: function (a, b, c) { /* ... */ },
    action: function (a, b, c) { /* ... */ }
  }
  // ...
]

// 每个职责一旦匹配,原函数就会直接返回。functiondemo (a, b, c) {
  for (let i = 0; i < rules.length; i++) {
    if (rules[i].match(a, b, c)) {
      return rules[i].action(a, b, c)
    }
  }
}
复制代码
引申话题——如何降低if else代码的复杂度?
相关文章阅读: 如何无痛降低 if else 面条代码复杂度 建议多读几次!!!

三、小结

本文粗略介绍了8种优化/替代if-else的方法,希望能给你日常编码带来一些启示😄。

正如开头所说,我们的目的不是消灭代码中的if-else,而是让我们在学会更多解决方案的基础上,根据实际情况选择更优的编码方式。因此,当你发现自己的代码里面存在特别多的if-else或当你想用if-else时,不妨停下来思考一下——如何能写得更优雅、更方便日后维护呢

大厂面试题分享 面试题库

前后端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库

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

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

相关文章

.NET 8 预览版 1 发布!

.NET 8 是一个长期支持(LTS) 版本。这篇文章涵盖了推动增强功能优先级排序和选择开发的主要主题和目标。.NET 8 预览版和发布候选版本将每月交付一次。像往常一样&#xff0c;最终版本将在 11 月的某个时候在 .NET Conf 上发布。 .NET 版本包括产品、库、运行时和工具&#xf…

JavaSE学习笔记总结day19

今日内容 二、线程安全的集合 三、死锁 四、线程通信 五、生产者消费者 六、线程池 零、 复习昨日 创建线程的几种方式 1) 继承 2) 实现Runnable 3) callable接口 Future接口 4) 线程池 启动线程的方法 start() 线程的几种状态 什么是线程不安全 setName getName Thread.curr…

基于intel soc+fpga智能驾驶舱和高级驾驶辅助系统软件设计(三)

虚拟化操作系统介绍 车载平台有逐渐融合的趋势&#xff0c;车载 SoC 的计算性能和应用快速增长&#xff0c;面临着多种应用在 多个显示子系统融合在一起的问题&#xff0c;这就要求平台运行多个操作系统。虚拟化&#xff08;Virtualization&#xff09; 技术飞速发展&#xff0…

软件测试培训三个月,找到工作了11K,面试总结分享给大家

功能方面&#xff1a;问的最多的就是测试流程&#xff0c;测试计划包含哪些内容&#xff0c;公司人员配置&#xff0c;有bug开发认为不是 bug怎么处理&#xff0c;怎样才算是好的用例&#xff0c;测试用例设计方法&#xff08;等价类&#xff0c;边界值等概念方法&#xff09;&…

ETL的模式以及优缺点

首先&#xff0c;ETL有四种主要实现模式&#xff1a;触发器模式、增量字段、全量同步、日志比对。其次&#xff0c;四种模式的优缺点触发器模式优点&#xff1a;数据抽取的性能高&#xff0c;ETL 加载规则简单&#xff0c;速度快&#xff0c;不需要修改业务系统表结构&#xff…

科目二练习与考试点位总结

一&#xff0c;开车前检查1.调整桌椅。2.调整左右后视镜。3.系安全带。二、倒车入库右边倒车直行至左肩与左虚线重合停车&#xff0c;倒车&#xff0c;左视镜下沿与左虚线重合或10cm左右&#xff0c;方向盘右打满。看右视镜第二个虚线一半回一圈。看右视镜右库角消失右打满。观…

Qt音视频开发20-vlc内核动态保存录像文件(不需要重新编译源码)

一、前言 在vlc默认提供的保存文件方式中&#xff0c;通过打开的时候传入指定的参数来保存文件&#xff0c;直到关闭播放生成文件&#xff0c;这种方式简单暴力&#xff0c;但是不适用大部分的场景&#xff0c;大部分时候需要的是提供开始录制和停止录制的功能&#xff0c;也就…

【springmvc】Rest ful风格

RESTful 1、RESTful简介 REST&#xff1a;Representational State Transfer&#xff0c;表现层资源状态转移。 a>资源 资源是一种看待服务器的方式&#xff0c;即&#xff0c;将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一…

华为OD机试题,用 Java 解【获取最大软件版本号】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

如何用MD5和SHA等构造密码方案中的哈希函数

文章目录常见符号如何实现 H:{0,1}∗→Zp∗H : \{0, 1\}^* \to \mathbb{Z}^*_pH:{0,1}∗→Zp∗​如何实现 H:Zp∗→{0,1}λH: \mathbb{Z}^*_p \to \{0, 1\}^\lambdaH:Zp∗​→{0,1}λ如何实现 H:M→ZN∗H: \mathcal{M} \to \mathbb{Z}^*_NH:M→ZN∗​如何实现 H:{0,1}∗→GH: \…

ElasticSearch - ElasticSearch基本概念及集群内部原理

文章目录1. ElasticSearch的应用场景01. Elasticsearch 是什么&#xff1f;02. 为何使用 Elasticsearch&#xff1f;03. Elasticsearch 的用途是什么&#xff1f;04. Elasticsearch 的工作原理是什么&#xff1f;05. Elasticsearch 索引是什么&#xff1f;06. Logstash 的用途是…

SAP UI5 Upload/Download file through NetWeaver Gateway

1、创建 SEGW对象 2、创建Entity Type 要把Media 标识打上 3、 激活对象然后到DPC Class的扩展对象里面重定义 /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_STREAM /IWBEP/IF_MGW_APPL_SRV_RUNTIME~UPDATE_STREAM METHOD /iwbep/if_m…

手写操作系统+文件系统开源啦

哈喽&#xff0c;我是子牙&#xff0c;一个很卷的硬核男人。喜欢研究底层&#xff0c;聚焦做那些大家想学没地方学的课程&#xff1a;手写操作系统、手写虚拟机、手写模拟器、手写编程语言… 今年是我创业的第二年&#xff0c;已经做了两个课程&#xff1a;手写JVM、手写操作系…

十五、Spring中的八大模式

1 简单工厂模式 BeanFactory的getBean()方法&#xff0c;通过唯一标识来获取Bean对象。是典型的简单工厂模式&#xff08;静态工厂模式&#xff09;&#xff1b; 2 工厂方法模式 FactoryBean是典型的工厂方法模式。在配置文件中通过factory-method属性来指定工厂方法&#x…

多线程的创建、Thread类、线程安全、同步、通信

目录 多线程的创建 方式一&#xff1a;继承Thread类 方式二&#xff1a;实现Runnable接口 方式三&#xff1a;JDK 5.0新增&#xff1a;实现Callable接口 Thread的常用方法 线程安全 线程安全问题是什么、发生的原因 线程安全问题案例模拟 线程同步 同步思想概述 方式…

0202state详解-组件-React

文章目录1 state简介2 初始化state3 React中事件绑定4 类方法中this指向问题5 解决React类组件方法this指向5 setState5.1 更新state状态数据方式5.2 更新state整体替换还是合并相同项&#xff1f;5.3 关于构造器、render方法调用次数6 state简写7 问题解答后记1 state简介 Re…

在NVIDIA JetBot Nano小车上更新WIFI驱动

前言:树莓派上的WIFI驱动类型比较多&#xff0c;经常有更好驱动的需求本文给出RealTek的无线WIFI模组&#xff0c;8821CU的驱动更新办法步骤第一 通过其他方式连接网络小车通过网线或者老的WIFI连接到网络上第二 构建驱动模块并下载驱动首先&#xff0c;我们需要打开一个ubuntu…

【深度学习】BERT变体—RoBERTa

RoBERTa是的BERT的常用变体&#xff0c;出自Facebook的RoBERTa: A Robustly Optimized BERT Pretraining Approach。来自Facebook的作者根据BERT训练不足的缺点提出了更有效的预训练方法&#xff0c;并发布了具有更强鲁棒性的BERT&#xff1a;RoBERTa。 RoBERTa通过以下四个方面…

【JavaEE】基于mysql与servlet自制简易的表白墙程序

文章目录1 表白墙页面构建2 Servlet 回顾3 表白墙后端程序实现3.1 我们需要做什么&#xff1f;3.2 实现细节4 实现结果写在最后1 表白墙页面构建 该页面由标题、文本、三个 input 输入框与一个提交按钮构成&#xff0c;整体比较简单&#xff0c;相关样式文件和页面代码会在后面…

【16】linux命令每日分享——tail命令查看文件

大家好&#xff0c;这里是sdust-vrlab&#xff0c;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;Linux的基本思想有两点&#xff1a;一切都是文件&#xff1b;每个文件都有确定的用途&#xff1b;linux涉及到IT行业的方方面面&#xff0c;在我们日常的学习中&…