js条件控制语句最佳实践
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条件控制语句最佳实践相关推荐
- 关于 JS 模块化的最佳实践总结
模块化开发是 JS 项目开发中的必备技能,它如同面向对象.设计模式一样,可以兼顾提升软件项目的可维护性和开发效率. 模块之间通常以全局对象维系通讯.在小游戏中,GameGlobal 是全局对象.在小程 ...
- Node.js CLI 工具最佳实践
为什么写这篇文章? 一个糟糕的 CLI 工具会让用户觉得难用,而构建一个成功的 CLI 需要密切关注很多细节,同时需要站在用户的角度,创造良好的用户体验.要做到这些特别不容易. 在这个指南中,我列出了 ...
- 使用 Node.js Express 的最佳实践
Production best practices: performance and reliability 本文讨论部署到生产的 Express 应用程序的性能和可靠性最佳实践. 这个话题显然属于& ...
- js函数式编程最佳实践 - 持续更新
函数式编程最佳实践 学习文档 函数式编程术语 数组字串处理 function addString(el){return el + "0"; } var newArr = arr.m ...
- vue main.js中引入js_web前端的同学不容错过,大厂Vue最佳实践总结,提高竞争力...
随着这几年前端技术的快速发展,Vue框架在国内普及率极高,人人都会用.那么,如何才能写得比别人优雅?比别人漂亮? 鉴于一线互联网大厂在前沿技术领域的持续研究和大规模投入,直接向他们取经,是最便捷也是最 ...
- JS最佳实践——红皮书
最佳实践 前言 1 可维护性 2 降低耦合 2.1 将css从js中抽离 2.2 模板文本写注释 2.3 应用逻辑 / 事件处理程序分离 2.3.1 概念 2.3.2 Demo 2.4 松散耦合原则 ...
- Vue.js 最佳实践清单,照亮你的开发之路
作者简介: 李中凯老师,8年前端开发,前端负责人,擅长JavaScript/Vue. 公众号:1024译站 掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b5800 ...
- JS(高程)最佳实践
在阅读js高程最佳实践章节,将自己感触比较深的点记录下来,也就是自已以前没注意或者不知道的知识点. 一.什么是可维护的代码? 可理解性 直观性 可适应性 可扩展性 可调式性 二.代码约定 1.函数和方 ...
- React.js 2016 最佳实践 徬梓阅读 1584收藏 71
为什么80%的码农都做不了架构师?>>> 译者按:近几个月React相关话题依旧火热,相信越来越多的开发者在尝试这样一项技术,我们团队也在PC和移动端不断总结经验.2016来了 ...
最新文章
- 使用Redis存储Nginx+Tomcat负载均衡集群的Session
- windows查看进程线程的命令pslist
- 使用DbContextPool提高EfCore查询性能
- 3617. 子矩形计数
- 用HTML做一个简单的web登录页面,简单的JavaWeb注册登录案例
- Linux系统编程9:进程入门之操作系统为什么这么重要以及它是如何实现管理的
- 安装在电脑上的网络测试软件,iperf3 网络测试工具
- 用命令行批处理bat,设置代理服务器、DNS、网关、WINS等
- nlp基础—9.条件随机场模型(CRF算法)
- 禅道类似软件_推荐几款不错的项目管理软件
- 融云 SDK 5.0.0 功能迭代
- swagger分页查询报错500
- DZS-115/DC110V中间继电器
- [Maven] 无法获取私服最新Jar包的问题
- 【Java工程中出现问题】XXX has been compiled by a more recent version of the Java Runtime
- sougou linux 无法切换中英文,Ubuntu 16.04安装GoLand后不能切换到搜狗输入法
- android:ellipsize
- 【Vivado那些事】关于reset_project和reset_project -exclude ip使用
- 接私活必备的几个开源项目!收藏
- java sqlldr_java调用sqlldr报错:Message 2100 not found
热门文章
- 塑料袋 (Demo) (《缝纫机乐队》电影插曲) - 缝纫机乐队
- 修复老照片软件有哪些?这3个工具帮你重拾美好回忆
- oracle install manually(手动建库)
- upload -labs通关解析及上传类型总结和思考
- 理想国Java学生管理系统实战教程+源码
- python高等教育教材_《全国高等职业教育“十三五”规划教材PYTHON程序设计/赵增敏》【价格 目录 书评 正版】_中国图书网...
- Go redis连接池
- UnityShader入门精要——表面着色器
- (数据结构)二叉树先序遍历
- python输出数字和字符串_Python中的数值和字符串