if else、switch case 是日常开发中最常见的条件判断语句,这种看似简单的语句,当遇到复杂的业务场景时,如果处理不善,就会出现大量的逻辑嵌套,可读性差并且难以扩展。

编写高质量可维护的代码,我们先从最小处入手,一起来看看在前端开发过程中,可以从哪些方面来优化逻辑判断?

下面我们会分别从 JavaScript 语法和 React JSX 语法两个方面来分享一些优化的技巧。

JavaScript 语法篇

嵌套层级优化

function supply(fruit, quantity) {  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];  // 条件 1: 水果存在  if(fruit) {    // 条件 2: 属于红色水果    if(redFruits.includes(fruit)) {      console.log('红色水果');      // 条件 3: 水果数量大于 10 个      if (quantity > 10) {        console.log('数量大于 10 个');      }    }  } else {    throw new Error('没有水果啦!');  }}

分析上面的条件判断,存在三层 if 条件嵌套。

如果提前 return 掉无效条件,将 if else 的多重嵌套层次减少到一层,更容易理解和维护。

function supply(fruit, quantity) {  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];  if(!fruit) throw new Error('没有水果啦');     // 条件 1: 当 fruit 无效时,提前处理错误  if(!redFruits.includes(fruit)) return; // 条件 2: 当不是红色水果时,提前 return

  console.log('红色水果');

  // 条件 3: 水果数量大于 10 个  if (quantity > 10) {    console.log('数量大于 10 个');  }}

多条件分支的优化处理

当需要枚举值处理不同的业务分支逻辑时,第一反应是写下 if else ?我们来看一下:

function pick(color) {  // 根据颜色选择水果  if(color === 'red') {    return ['apple', 'strawberry'];   } else if (color === 'yellow') {    return ['banana', 'pineapple'];  } else if (color === 'purple') {    return ['grape', 'plum'];  } else {    return [];  }}

在上面的实现中:

  • if else 分支太多
  • if else 更适合于条件区间判断,而 switch case 更适合于具体枚举值的分支判断

使用 switch case 优化上面的代码后:

function pick(color) {  // 根据颜色选择水果  switch (color) {    case 'red':      return ['apple', 'strawberry'];    case 'yellow':      return ['banana', 'pineapple'];    case 'purple':      return ['grape', 'plum'];    default:      return [];  }}

switch case 优化之后的代码看上去格式整齐,思路很清晰,但还是很冗长。继续优化:

  • 借助 Object 的 { key: value } 结构,我们可以在 Object 中枚举所有的情况,然后将 key 作为索引,直接通过 Object.key 或者 Object[key] 来获取内容
const fruitColor = {                          red: ['apple', 'strawberry'],  yellow: ['banana', 'pineapple'],  purple: ['grape', 'plum'],}function pick(color) {  return fruitColor[color] || [];}
  • 使用 Map 数据结构,真正的 (key, value) 键值对结构;

const fruitColor = new Map().set('red', ['apple', 'strawberry']).set('yellow', ['banana', 'pineapple']).set('purple', ['grape', 'plum']);

function pick(color) {  return fruitColor.get(color) || [];}

优化之后,代码更简洁、更容易扩展。

为了更好的可读性,还可以通过更加语义化的方式定义对象,然后使用 Array.filter 达到同样的效果。

const fruits = [  { name: 'apple', color: 'red' },   { name: 'strawberry', color: 'red' },   { name: 'banana', color: 'yellow' },   { name: 'pineapple', color: 'yellow' },   { name: 'grape', color: 'purple' },   { name: 'plum', color: 'purple' }];

function pick(color) {  return fruits.filter(f => f.color == color);}

使用数组新特性简化逻辑判断

巧妙的利用 ES6 中提供的数组新特性,也可以让我们更轻松的处理逻辑判断。

多条件判断

编码时遇到多个判断条件时,本能的写下下面的代码(其实也是最能表达业务逻辑的面向过程编码)。

function judge(fruit) {  if (fruit === 'apple' || fruit === 'strawberry' || fruit === 'cherry' || fruit === 'cranberries' ) {    console.log('red');  }}

但是当 type 未来到 10 种甚至更多时, 我们只能继续添加 || 来维护代码么?

试试 Array.includes ~

// 将判断条件抽取成一个数组const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];function judge(type) {  if (redFruits.includes(fruit)) {    console.log('red');  }}

判断数组中是否所有项都满足某条件

const fruits = [  { name: 'apple', color: 'red' },  { name: 'banana', color: 'yellow' },  { name: 'grape', color: 'purple' }];

function match() {  let isAllRed = true;

  // 判断条件:所有的水果都必须是红色  for (let f of fruits) {    if (!isAllRed) break;    isAllRed = (f.color === 'red');  }

  console.log(isAllRed); // false}

上面的实现中,主要是为了处理数组中的所有项都符合条件。

使用 Array.every 可以很容的实现这个逻辑:

const fruits = [  { name: 'apple', color: 'red' },  { name: 'banana', color: 'yellow' },  { name: 'grape', color: 'purple' }];

function match() {  // 条件:所有水果都必须是红色  const isAllRed = fruits.every(f => f.color == 'red');

  console.log(isAllRed); // false}

判断数组中是否有某一项满足条件

Array.some,它主要处理的场景是判断数组中是否有一项满足条件。

如果想知道是否有红色水果,可以直接使用 Array.some 方法:

const fruits = [    { name: 'apple', color: 'red' },    { name: 'banana', color: 'yellow' },    { name: 'grape', color: 'purple' }  ];

// 条件:是否有红色水果 const isAnyRed = fruits.some(f => f.color == 'red');

还有许多其他数组新特性,比如 Array.find、Array.slice、Array.findIndex、Array.reduce、Array.splice 等,在实际场景中可以根据需要选择使用。

函数默认值

使用默认参数

const buyFruit = (fruit,amount) => {  if(!fruit){    return  }  amount = amount || 1;  console.log(amount)}

我们经常需要处理函数内部的一些参数默认值,上面的代码大家都不陌生,使用函数的默认参数,可以很好的帮助处理这种场景。

const buyFruit = (fruit,amount = 1) => {  if(!fruit){    return  }  console.log(amount,'amount')}

我们可以通过 Babel 的转译来看一下默认参数是如何实现的。


从上面的转译结果可以发现,只有参数为 undefined 时才会使用默认参数。

测试的执行结果如下:

buyFruit('apple','');  // amountbuyFruit('apple',null);  //null amountbuyFruit('apple');  //1 amount

所以使用默认参数的情况下,我们需要注意的是默认参数 amount = 1 并不等同于 amount || 1

使用解构与默认参数

当函数参数是对象时,我们可以使用解构结合默认参数来简化逻辑。

Before:

const buyFruit = (fruit,amount) => { fruit = fruit || {}; if(!fruit.name || !fruit.price){   return; } ...  amount = amount || 1;  console.log(amount)}

After:

const buyFruit = ({ name,price }={},amount) => {  if(!name || !prices){    return;  }  console.log(amount)}

复杂数据解构

当处理比较简的对象时,解构与默认参数的配合是非常好的,但在一些复杂的场景中,我们面临的可能是更复杂的结构。

const oneComplexObj = { firstLevel: {   secondLevel:[{     name:"",     price:""   }]  }}

这个时候如果再通过解构去获取对象里的值。

const {  firstLevel:{    secondLevel:[{name,price]=[]  }={}} = oneComplexObj;              

可读性就会比较差,而且需要考虑多层解构的默认值以及数据异常情况。

这种情况下,如果项目中使用 lodash 库,可以使用其中的 lodash/get 方法。

import lodashGet from 'lodash/get';

const { name,price} = lodashGet(oneComplexObj,'firstLevel.secondLevel[0]',{});

策略模式优化分支逻辑处理

策略模式:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

使用场景:策略模式属于对象行为模式,当遇到具有相同行为接口、行为内部不同逻辑实现的实例对象时,可以采用策略模式;或者是一组对象可以根据需要动态的选择几种行为中的某一种时,也可以采用策略模式;这里以第二种情况作为示例:

Before:

const TYPE = {  JUICE:'juice',  SALAD:'salad',  JAM:'jam'}function enjoy({type = TYPE.JUICE,fruits}){  if(!fruits || !fruits.length) {    console.log('请先采购水果!');    return; }  if(type === TYPE.JUICE) {    console.log('榨果汁中...');    return '果汁';  }  if(type === TYPE.SALAD) {    console.log('做沙拉中...');    return '拉沙';  }  if(type === TYPE.JAM) {    console.log('做果酱中...');    return '果酱';  }  return;}

enjoy({type:'juice',fruits});

使用思路:定义策略对象封装不同行为、提供策略选择接口,在不同的规则时调用相应的行为。

After:

const TYPE = {  JUICE:'juice',  SALAD:'salad',  JAM:'jam'}

const strategies = {  [TYPE.JUICE]: function(fruits){    console.log('榨果汁中...');    return '果汁';  },  [TYPE.SALAD]:function(fruits){    console.log('做沙拉中...');    return '沙拉';  },  [TYPE.JAM]:function(fruits){    console.log('做果酱中...');    return '果酱';  },}

function enjoy({type = TYPE.JUICE,fruits}) {  if(!type) {    console.log('请直接享用!');    return; }  if(!fruits || !fruits.length) {    console.log('请先采购水果!');    return; }   return strategies[type](fruits);}

enjoy({type:'juice',fruits});

框架篇之 React JSX 逻辑判断优化

JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。一般在 React 中使用 JSX 来描述界面信息,ReactDOM.render() 将 JSX 界面信息渲染到页面上。

在 JSX 中支持 JavaScript 表达式,日常很常见的循环输出子组件、三元表达式判断、再复杂一些直接抽象出一个函数。

在 JSX 中写这么多  JavaScript 表达式,整体代码看起来会有点儿杂乱。试着优化一下!

JSX-Control-Statements

JSX-Control-Statements (https://www.npmjs.com/package/jsx-control-statements) 是一个 Babel 插件,它扩展了 JSX 的能力,支持以标签的形式处理条件判断、循环。

If 标签

标签内容只有在 condition 为 true 时才会渲染,等价于最简单的三元表达式。

Before:

{ condition() ? 'Hello World!' : null }   

After:

<If condition={ condition() }>Hello World!If>   

注意:已被废弃,复杂的条件判断可以使用标签。

Choose 标签

标签下包括至少一个标签、可选的标签。

标签内容只有在 condition 为 true 时才会渲染,相当于一个 if 条件判断分支。

标签则相当于最后的 else 分支。

Before:

{ test1 ? <span>IfBlock1span> : test2 ? <span>IfBlock2span> : <span>ElseBlockspan> }

After:

<Choose>  <When condition={ test1 }><span>IfBlock1span>When>  <When condition={ test2 }><span>IfBlock2span>When>  <Otherwise><span>ElseBlockspan>Otherwise>Choose>

For 标签

标签需要声明 of、each 属性。

of 接收的是可以使用迭代器访问的对象。

each 代表迭代器访问时的当前指向元素。

Before:

{  (this.props.items || []).map(item => {    return <span key={ item.id }>{ item.title }span>  })}

After:

<For each="item" of={ this.props.items }>  <span key={ item.id }>{ item.title }span>For>

注意:标签不能作为根元素。

With 标签

标签提供变量传参的功能。

Before:

renderFoo = (foo) => {  return <span>{ foo }span>;}

// JSX 中表达式调用{  this.renderFoo(47)}

After:

<With foo={ 47 }>  <span>{ foo }span>With>

使用这几种标签优化代码,可以减少  JSX 中存在的显式 JavaScript 表达式,使我们的代码看上去更简洁,但是这些标签封装的能力,在编译时需要转换为等价的 JavaScript 表达式。

注意:具体 babel-plugin-jsx-control-statements 插件的使用见第三篇参考文章;Vue 框架已经通过指令的形式支持 v-if、v-else-if、v-else、v-show、slot 等。

总结

以上我们总结了一些常见的逻辑判断优化技巧。当然,编写高质量可维护的代码,除了逻辑判断优化,还需要有清晰的注释、含义明确的变量命名、合理的代码结构拆分、逻辑分层解耦、以及更高层次的贴合业务的逻辑抽象等等,相信各位在这方面也有自己的一些心得,欢迎一起留言讨论~

参考文献

  • 5 Tips to Write Better Conditionals in JavaScript (https://scotch.io/bar-talk/5-tips-to-write-better-conditionals-in-javascript)
  • stop-putting-so-many-if-statements-in-your-javascript (https://medium.com/better-programming/stop-putting-so-many-if-statements-in-your-javascript-3b65aaa4b86b)
  • JSX Control Statements (https://www.npmjs.com/package/jsx-control-statements)

看完两件事

如果你觉得这篇内容对你挺有启发,我想邀请你帮我两件小事1.点个「在看」,让更多人也能看到这篇内容(点了「在看」,bug -1 ?)2.关注公众号「前端公虾米」,持续为你推送精选好文

判断某值是否属于枚举类中的值_编写高质量可维护的代码之优化逻辑判断相关推荐

  1. python中如何编写代码输入多个数据并把它们放在一个列表中去_编写高质量Python代码的59个有效方法,你用过几个...

    欢迎点击右上角关注小编,除了分享技术文章之外还有很多福利,私信学习资料可以领取包括不限于Python实战演练.PDF电子文档.面试集锦.学习资料等. 这个周末断断续续的阅读完了<Effectiv ...

  2. java代码优化的方法和准则_编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议16~20)...

    建议16:易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP,Ruby,Groovy.Javascript等,这些入侵者都有一个共同特征:全是同一类语言-----脚本语言,它 ...

  3. java代码异常处理会影响性能_编写高质量代码改善java程序的151个建议——[110-117]异常及Web项目中异常处理...

    原创地址:http://www.cnblogs.com/Alandre/(泥沙砖瓦浆木匠),需要转载的,保留下! 文章宗旨:Talk is cheap show me the code. 大成若缺,其 ...

  4. 枚举类中获取枚举值的几种方法

    在开发的过程中我们经常会定义枚举类,枚举类中获取枚举值的方式也有很多种,下面我们就探究一下大家常用的几种方式: 枚举类 public enum TestEnum {ONE(1,"one&qu ...

  5. java枚举类中字段有没有必要加final____枚举类字段 Field ‘xxx‘ may be ‘final‘

    java枚举类中字段有没有必要加final 今天在写一个系统统一返回码的枚举类时候,突然想到一个问题,当不小心手抖给枚举类自动生成了set方法,而恰巧在用的地方不小心用了set方法,从而修改了code ...

  6. 利用多态特性,编程创建一个手机类Phones,定义打电话方法call()。创建两个子类:苹果手机类IPhone和安卓手机类APhone,并在各自类中重写方法call(),编写程序入口main()方法

    利用多态特性,编程创建一个手机类Phones,定义打电话方法call().创建两个子类:苹果手机类IPhone和安卓手机类APhone,并在各自类中重写方法call(),编写程序入口main()方法, ...

  7. 编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议1~5)...

                 The reasonable man adapts himself to the world; The unreasonable one persists in trying ...

  8. python中如何编写代码输入多个数据并把它们放在一个列表中去_这59条编写高质量Python代码的方法你知道吗?...

    这个周末断断续续的阅读完了<Effective Python之编写高质量Python代码的59个有效方法>,感觉还不错,具有很大的指导价值. 下面将以最简单的方式记录这59条建议,并在大部 ...

  9. 转载----编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议1~5)...

    阅读目录 建议1:不要在常量和变量中出现易混淆的字母 建议2:莫让常量蜕变成变量 建议3:三元操作符的类型务必一致 建议4:避免带有变长参数的方法重载 建议5:别让null值和空值威胁到变长方法    ...

最新文章

  1. 用Jmeter实现SQLServer数据库的增删查改
  2. PHP获取文件后缀名
  3. java实用教程——组件及事件处理——ItemEvent事件(设置字体类型)
  4. 分析酸对酸性染料染羊毛染色性能的影响?举例说明酸性染料染羊毛时,如何选择合适的染浴pH值?并说明原因。
  5. ie浏览器剪贴板操作警告弹窗关闭方法
  6. canal client leader
  7. Shape Number (最小表示法)
  8. Centos 7 环境下,如何使用 Apache 实现 SSL 虚拟主机 双向认证 的详细教程:
  9. 清华姚班和100个张小龙
  10. 遥感大辞典_学遥感必读的十本书
  11. Android中获取并设置屏幕亮度
  12. ET5.0 简单了解
  13. 计算机网络适配器高级属性,右击我的电脑——属性——设备管理器——1394网络适配器下面那个选项右击属性——高级——大量传送减负——...
  14. 三种嵌入式操作系统(Palm OS 、Windows CE 和Linux)的深入分析与比较
  15. 用python画一个机器猫歌词_Python实现海贼王的歌词组成词云图
  16. opencv3.2教程linux,Linux编译OpenCV3.2.0-OCL模块并使用
  17. win32 010 使用masm32
  18. 【Android Compose】实现宜家 双联列表
  19. 锐化 清晰度 对比度的区别
  20. labelcommand打印条码_VB应用程序中打印条形码的方法

热门文章

  1. 基于比特币现金BCH二层网络能实现区块链2.0以太坊的智能化吗
  2. Bitcoin.com推出BCH新图表,加大对BCH的支持
  3. 大数据技术学习路线,有信心能坚持学习的朋友,从现在开始吧
  4. JS中的call、apply、bind方法详解
  5. Android 开发应该掌握的 Proguard 技巧
  6. 设计一条简单的等待工作队列之软件模型设计与实现(二)
  7. easyui datagrid checkbox的相关属性整理
  8. 一张图解释SQL Server集群、镜像、复制、日志传送
  9. ASP.Net定时任务执行
  10. 配合使用自制的PE3.0启动盘和Windows部署服务,实现Ghost网克