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

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

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: 当不是红色水果时,提前 returnconsole.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','');  // amount
buyFruit('apple',null);  //null amount
buyFruit('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});

完结撒花,有疑问留言探讨哈~~~

js条件控制语句最佳实践相关推荐

  1. 关于 JS 模块化的最佳实践总结

    模块化开发是 JS 项目开发中的必备技能,它如同面向对象.设计模式一样,可以兼顾提升软件项目的可维护性和开发效率. 模块之间通常以全局对象维系通讯.在小游戏中,GameGlobal 是全局对象.在小程 ...

  2. Node.js CLI 工具最佳实践

    为什么写这篇文章? 一个糟糕的 CLI 工具会让用户觉得难用,而构建一个成功的 CLI 需要密切关注很多细节,同时需要站在用户的角度,创造良好的用户体验.要做到这些特别不容易. 在这个指南中,我列出了 ...

  3. 使用 Node.js Express 的最佳实践

    Production best practices: performance and reliability 本文讨论部署到生产的 Express 应用程序的性能和可靠性最佳实践. 这个话题显然属于& ...

  4. js函数式编程最佳实践 - 持续更新

    函数式编程最佳实践 学习文档 函数式编程术语 数组字串处理 function addString(el){return el + "0"; } var newArr = arr.m ...

  5. vue main.js中引入js_web前端的同学不容错过,大厂Vue最佳实践总结,提高竞争力...

    随着这几年前端技术的快速发展,Vue框架在国内普及率极高,人人都会用.那么,如何才能写得比别人优雅?比别人漂亮? 鉴于一线互联网大厂在前沿技术领域的持续研究和大规模投入,直接向他们取经,是最便捷也是最 ...

  6. JS最佳实践——红皮书

    最佳实践 前言 1 可维护性 2 降低耦合 2.1 将css从js中抽离 2.2 模板文本写注释 2.3 应用逻辑 / 事件处理程序分离 2.3.1 概念 2.3.2 Demo 2.4 松散耦合原则 ...

  7. Vue.js 最佳实践清单,照亮你的开发之路

    作者简介: 李中凯老师,8年前端开发,前端负责人,擅长JavaScript/Vue. 公众号:1024译站 掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b5800 ...

  8. JS(高程)最佳实践

    在阅读js高程最佳实践章节,将自己感触比较深的点记录下来,也就是自已以前没注意或者不知道的知识点. 一.什么是可维护的代码? 可理解性 直观性 可适应性 可扩展性 可调式性 二.代码约定 1.函数和方 ...

  9. React.js 2016 最佳实践 徬梓阅读 1584收藏 71

    为什么80%的码农都做不了架构师?>>>    译者按:近几个月React相关话题依旧火热,相信越来越多的开发者在尝试这样一项技术,我们团队也在PC和移动端不断总结经验.2016来了 ...

最新文章

  1. 使用Redis存储Nginx+Tomcat负载均衡集群的Session
  2. windows查看进程线程的命令pslist
  3. 使用DbContextPool提高EfCore查询性能
  4. 3617. 子矩形计数
  5. 用HTML做一个简单的web登录页面,简单的JavaWeb注册登录案例
  6. Linux系统编程9:进程入门之操作系统为什么这么重要以及它是如何实现管理的
  7. 安装在电脑上的网络测试软件,iperf3 网络测试工具
  8. 用命令行批处理bat,设置代理服务器、DNS、网关、WINS等
  9. nlp基础—9.条件随机场模型(CRF算法)
  10. 禅道类似软件_推荐几款不错的项目管理软件
  11. 融云 SDK 5.0.0 功能迭代
  12. swagger分页查询报错500
  13. DZS-115/DC110V中间继电器
  14. [Maven] 无法获取私服最新Jar包的问题
  15. 【Java工程中出现问题】XXX has been compiled by a more recent version of the Java Runtime
  16. sougou linux 无法切换中英文,Ubuntu 16.04安装GoLand后不能切换到搜狗输入法
  17. android:ellipsize
  18. 【Vivado那些事】关于reset_project和reset_project -exclude ip使用
  19. 接私活必备的几个开源项目!收藏
  20. java sqlldr_java调用sqlldr报错:Message 2100 not found

热门文章

  1. 塑料袋 (Demo) (《缝纫机乐队》电影插曲) - 缝纫机乐队
  2. 修复老照片软件有哪些?这3个工具帮你重拾美好回忆
  3. oracle install manually(手动建库)
  4. upload -labs通关解析及上传类型总结和思考
  5. 理想国Java学生管理系统实战教程+源码
  6. python高等教育教材_《全国高等职业教育“十三五”规划教材PYTHON程序设计/赵增敏》【价格 目录 书评 正版】_中国图书网...
  7. Go redis连接池
  8. UnityShader入门精要——表面着色器
  9. (数据结构)二叉树先序遍历
  10. python输出数字和字符串_Python中的数值和字符串