JavaScript 编写更好的条件语句
在任何编程语言中,代码需要根据不同的条件在给定的输入中做不同的决定和执行相应的动作。
例如,在一个游戏中,如果玩家生命点为0,游戏结束。在天气应用中,如果在早上被查看,显示一个日出图片,如果是晚上,则显示星星和月亮。在这篇文章中,我们将探索JavaScript中所谓的条件语句如何工作。
如果你使用JavaScript工作,你将写很多包含条件调用的代码。条件调用可能初学很简单,但是还有比写一对对if/else更多的东西。这里有些编写更好更清晰的条件代码的有用提示。
-
数组方法 Array.includes
-
提前退出 / 提前返回
-
用对象字面量或Map替代Switch语句
-
默认参数和解构
-
用 Array.every & Array.some 匹配全部/部分内容
-
使用可选链和空值合并
1、数组方法 Array.includes
使用 Array.includes
进行多条件选择
例如:
function printAnimals(animal) {if (animal === 'dog' || animal === 'cat') {console.log(I have a ${animal});}
}console.log(printAnimals('dog')); // I have a dog
上面的代码看起来很好因为我们只检查了两个动物。然而,我们不确定用户输入。如果我们要检查任何其他动物呢?如果我们通过添加更多“或”语句来扩展,代码将变得难以维护和不清晰。
解决方案:
我们可以通过使用 Array.includes
来重写上面的条件
function printAnimals(animal) {const animals = ['dog', 'cat', 'hamster', 'turtle']; if (animals.includes(animal)) {console.log(I have a ${animal});}
}console.log(printAnimals('hamster')); // I have a hamster
这里,我们创建来一个动物数组,所以条件语句可以和代码的其余部分抽象分离出来。现在,如果我们想要检查任何其他动物,我们只需要添加一个新的数组项。
我们也能在这个函数作用域外部使用这个动物数组变量来在代码中的其他任意地方重用它。这是一个编写更清晰、易理解和维护的代码的方法,不是吗?
2、提前退出 / 提前返回
这是一个精简你的代码的非常酷的技巧。我记得当我开始专业工作时,我在第一天学习使用提前退出来编写条件。
让我们在之前的例子上添加更多的条件。用包含确定属性的对象替代简单字符串的动物。
现在的需求是:
-
如果没有动物,抛出一个异常
-
打印动物类型
-
打印动物名字
-
打印动物性别
const printAnimalDetails = animal => {let result; // declare a variable to store the final value// condition 1: check if animal has a valueif (animal) {// condition 2: check if animal has a type propertyif (animal.type) {// condition 3: check if animal has a name propertyif (animal.name) {// condition 4: check if animal has a gender propertyif (animal.gender) {result = ${animal.name} is a ${animal.gender} ${animal.type};;} else {result = "No animal gender";}} else {result = "No animal name";}} else {result = "No animal type";}} else {result = "No animal";}return result;
};console.log(printAnimalDetails()); // 'No animal'console.log(printAnimalDetails({ type: "dog", gender: "female" })); // 'No animal name'console.log(printAnimalDetails({ type: "dog", name: "Lucy" })); // 'No animal gender'console.log(printAnimalDetails({ type: "dog", name: "Lucy", gender: "female" })
); // 'Lucy is a female dog'
你觉得上面的代码怎么样?
它工作得很好,但是代码很长并且维护困难。如果不使用lint工具,找出闭合花括号在哪都会浪费很多时间。😄 想象如果代码有更复杂的逻辑会怎么样?大量的if..else语句。
我们能用三元运算符、&&条件等语法重构上面的功能,但让我们用多个返回语句编写更清晰的代码。
const printAnimalDetails = ({type, name, gender } = {}) => {if(!type) return 'No animal type';if(!name) return 'No animal name';if(!gender) return 'No animal gender';// Now in this line of code, we're sure that we have an animal with all //the three properties here.return ${name} is a ${gender} ${type};
}console.log(printAnimalDetails()); // 'No animal type'console.log(printAnimalDetails({ type: dog })); // 'No animal name'console.log(printAnimalDetails({ type: dog, gender: female })); // 'No animal name'console.log(printAnimalDetails({ type: dog, name: 'Lucy', gender: 'female' })); // 'Lucy is a female dog'
在这个重构过的版本中,也包含了解构和默认参数。默认参数确保如果我们传递undefined作为一个方法的参数,我们仍然有值可以解构,在这里它是一个空对象{}。
通常,在专业领域,代码被写在这两种方法之间。
另一个例子:
function printVegetablesWithQuantity(vegetable, quantity) {const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus'];// condition 1: vegetable should be presentif (vegetable) {// condition 2: must be one of the item from the listif (vegetables.includes(vegetable)) {console.log(I like ${vegetable});// condition 3: must be large quantityif (quantity >= 10) {console.log('I have bought a large quantity');}}} else {throw new Error('No vegetable from the list!');}
}printVegetablesWithQuantity(null); // No vegetable from the list!
printVegetablesWithQuantity('cabbage'); // I like cabbage
printVegetablesWithQuantity('cabbage', 20);
// 'I like cabbage
// 'I have bought a large quantity'
现在,我们有:
-
1 if/else 语句过滤非法条件
-
3 级嵌套if语句 (条件 1, 2, & 3)
一个普遍遵循的规则是:在非法条件匹配时提前退出。
function printVegetablesWithQuantity(vegetable, quantity) {const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus'];// condition 1: throw error earlyif (!vegetable) throw new Error('No vegetable from the list!');// condition 2: must be in the listif (vegetables.includes(vegetable)) {console.log(I like ${vegetable});// condition 3: must be a large quantityif (quantity >= 10) {console.log('I have bought a large quantity');}}
}
通过这么做,我们少了一个嵌套层级。当你有一个长的if语句时,这种代码风格特别好。
我们能通过条件倒置和提前返回,进一步减少嵌套的if语句。查看下面的条件2,观察我们是怎么做的
function printVegetablesWithQuantity(vegetable, quantity) {const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus'];if (!vegetable) throw new Error('No vegetable from the list!'); // condition 1: throw error earlyif (!vegetables.includes(vegetable)) return; // condition 2: return from the function is the vegetable is not in // the list console.log(I like ${vegetable});// condition 3: must be a large quantityif (quantity >= 10) {console.log('I have bought a large quantity');}
}
通过倒置条件2,代码没有嵌套语句了。这种技术在我们有很多条件并且当任何特定条件不匹配时,我们想停止进一步处理的时候特别有用。
所以,总是关注更少的嵌套和提前返回,但也不要过度地使用。
3、用对象字面量或Map替代Switch语句
让我们来看看下面的例子,我们想要基于颜色打印水果:
function printFruits(color) {// use switch case to find fruits by colorswitch (color) {case 'red':return ['apple', 'strawberry'];case 'yellow':return ['banana', 'pineapple'];case 'purple':return ['grape', 'plum'];default:return [];}
}printFruits(null); // []
printFruits('yellow'); // ['banana', 'pineapple']
上面的代码没有错误,但是它仍然有些冗长。相同的功能能用对象字面量以更清晰的语法实现:
// use object literal to find fruits by colorconst fruitColor = {red: ['apple', 'strawberry'],yellow: ['banana', 'pineapple'],purple: ['grape', 'plum']};function printFruits(color) {return fruitColor[color] || [];
}
另外,你也能用 Map
来实现相同的功能:
// use Map to find fruits by colorconst fruitColor = new Map().set('red', ['apple', 'strawberry']).set('yellow', ['banana', 'pineapple']).set('purple', ['grape', 'plum']);function printFruits(color) {return fruitColor.get(color) || [];
}
Map
允许保存键值对,是自从ES2015以来可以使用的对象类型。
对于上面的例子,相同的功能也能用数组方法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 printFruits(color) {return fruits.filter(fruit => fruit.color === color);
}
4、默认参数和解构
当使用 JavaScript 工作时,我们总是需要检查 null/undefined
值并赋默认值,否则可能编译失败。
function printVegetablesWithQuantity(vegetable, quantity = 1) {
// if quantity has no value, assign 1if (!vegetable) return;console.log(We have ${quantity} ${vegetable}!);
}//results
printVegetablesWithQuantity('cabbage'); // We have 1 cabbage!
printVegetablesWithQuantity('potato', 2); // We have 2 potato!
如果 vegetable 是一个对象呢?我们能赋一个默认参数吗?
function printVegetableName(vegetable) { if (vegetable && vegetable.name) {console.log (vegetable.name);} else {console.log('unknown');}
}printVegetableName(undefined); // unknown
printVegetableName({}); // unknown
printVegetableName({ name: 'cabbage', quantity: 2 }); // cabbage
在上面的例子中,如果vegetable 存在,我们想要打印 vegetable name, 否则打印"unknown"。
我们能通过使用默认参数和解构来避免条件语句 if (vegetable && vegetable.name) {} 。
// destructing - get name property only
// assign default empty object {}function printVegetableName({name} = {}) {console.log (name || 'unknown');
}printVegetableName(undefined); // unknown
printVegetableName({ }); // unknown
printVegetableName({ name: 'cabbage', quantity: 2 }); // cabbage
因为我们只需要 name
属性,所以我们可以使用 { name }
解构参数,然后我们就能在代码中使用 name
作为变量,而不是 vegetable.name
。
我们还赋了一个空对象 {} 作为默认值,因为当执行 printVegetableName(undefined)
时会得到一个错误:不能从 undefined
或 null
解构属性 name
,因为在 undefined
中没有 name
属性。
5、用 Array.every & Array.some 匹配全部/部分内容
我们能使用数组方法减少代码行。查看下面的代码,我们想要检查是否所有的水果都是红色的:
const fruits = [{ name: 'apple', color: 'red' },{ name: 'banana', color: 'yellow' },{ name: 'grape', color: 'purple' }];function test() {let isAllRed = true;// condition: all fruits must be redfor (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 test() {// condition: short way, all fruits must be redconst isAllRed = fruits.every(f => f.color == 'red');console.log(isAllRed); // false
}
相似地,如果我们想测试是否有任何红色的水果,我们能用一行 Array.some
来实现它。
const fruits = [{ name: 'apple', color: 'red' },{ name: 'banana', color: 'yellow' },{ name: 'grape', color: 'purple' }
];function test() {// condition: if any fruit is redconst isAnyRed = fruits.some(f => f.color == 'red');console.log(isAnyRed); // true
}
6、使用可选链和空值合并
这有两个为编写更清晰的条件语句而即将成为 JavaScript 增强的功能。当写这篇文章时,它们还没有被完全支持,你需要使用 Babel 来编译。
可选链允许我们没有明确检查中间节点是否存在地处理 tree-like 结构,空值合并和可选链组合起来工作得很好,以确保为不存在的值赋一个默认值。
这有一个例子:
const car = {model: 'Fiesta',manufacturer: {name: 'Ford',address: {street: 'Some Street Name',number: '5555',state: 'USA'}}
} // to get the car model
const model = car && car.model || 'default model';// to get the manufacturer street
const street = car && car.manufacturer && car.manufacturer.address &&
car.manufacturer.address.street || 'default street';// request an un-existing property
const phoneNumber = car && car.manufacturer && car.manufacturer.address
&& car.manufacturer.phoneNumber;console.log(model) // 'Fiesta'
console.log(street) // 'Some Street Name'
console.log(phoneNumber) // undefined
所以,如果我们想要打印是否车辆生产商来自美国,代码将看起来像这样:
const isManufacturerFromUSA = () => {if(car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.state === 'USA') {console.log('true');}
}checkCarManufacturerState() // 'true'
你能清晰地看到当有一个更复杂的对象结构时,这能变得多乱。有一些第三方的库有它们自己的函数,像 lodash 或 idx。例如 lodash 有 _.get 方法。然而,JavaScript 语言本身被引入这个特性是非常酷的。
这展示了这些新特性如何工作:
// to get the car model
const model = car?.model ?? 'default model';// to get the manufacturer street
const street = car?.manufacturer?.address?.street ?? 'default street';// to check if the car manufacturer is from the USA
const isManufacturerFromUSA = () => {if(car?.manufacturer?.address?.state === 'USA') {console.log('true');}
}
这看起来很美观并容易维护。它已经到 TC39 stage 3 阶段,让我们等待它获得批准,然后我们就能无处不在地看到这难以置信的语法的使用。
相关文章:
JavaScript 编写更好的条件语句
在任何编程语言中,代码需要根据不同的条件在给定的输入中做不同的决定和执行相应的动作。 例如,在一个游戏中,如果玩家生命点为0,游戏结束。在天气应用中,如果在早上被查看,显示一个日出图片,如…...
聊聊PBE算法
序 本文主要研究一下PBE算法 PBE PBE即Password Based Encryption,基于口令的加密,它是一种组合算法,即一般是哈希对称算法,比如PBEWithMD5AndDES,就是用MD5做哈希,用DES做加解密,而其密钥则…...

用MFC打开外部程序
在MFC(Microsoft Foundation Classes)中,你可以使用ShellExecute函数来打开Notepad并加载指定的文件。ShellExecute函数是Windows API的一部分,它可以执行与操作系统相关的操作,例如打开文件、运行程序等。 以下是在M…...

基于全新电脑环境安装pytorch的GPU版本
前言: 距离第一次安装深度学习的GPU环境已经过去了4年多(当时TensorFlow特别麻烦),现在发现安装pytorch的GPU版本还是很简单方便的,流程记录如下。 安装步骤: 步骤一:官网下载Anaconda Free…...

[当前就业]2023年8月25日-计算机视觉就业现状分析
计算机视觉就业现状分析 前言:超越YOLO:计算机视觉市场蓬勃发展 如今,YOLO(You Only Look Once)新版本的发布周期很快,每次迭代的性能都优于其前身。每 3 到 4 个月就会推出一个升级版 YOLO 变体…...

虚拟化技术原理
计算虚拟化 介绍 把物理主机上物理资源(CPU,内存,IO外设),通过虚拟化层抽象成超量、等量的逻辑资源(虚拟CPU,虚拟内存,虚拟IO设备),然后重新组合形成新的虚…...
opencv-答题卡识别判卷
#导入工具包 import numpy as np import argparse import imutils import cv2# 设置参数 ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required=True,help="path to the input image") args = vars(ap.parse_args())# 正确…...

【Linux】基础IO
目录 一、回顾C语言文件操作二、文件系统调用接口1. open2.write3.read 三、文件描述符四、重定向1.输出重定向2.输入重定向 五、dup2 一、回顾C语言文件操作 1 #include<stdio.h>2 #include<stdlib.h>3 4 #define LOG "log.txt"5 6 int main()7 {8 //…...

【Go 基础篇】深入探索:Go语言中的二维数组
在计算机编程中,数组是一种基本的数据结构,用于存储相同类型的元素。而二维数组作为数组的一种扩展,允许我们以类似表格的方式存储和处理数据。在Go语言中,二维数组是一个重要的概念,本文将深入探讨Go语言中的二维数组…...

IntelliJ IDEA 2023.2.1使用Git时弹出“使用访问令牌登录”问题解决
这里写目录标题 一、内网Git环境GitLabGogsGitea 二、外网Git环境GitHubGitee 升级为IntelliJ IDEA 2023.2.1后,使用Git时弹出“使用访问令牌登录”的窗口,习惯使用Git帐号密码登录的用户,面对这个突如其来的弹窗真的很懵。 一、内网Git环境 …...

前端开发学习路线
无前端基础学习路线: B站免费视频1 B站免费视频2 有HTML、CSS、JavaScript基础,可直接通过以上视频中Vue2Vue3中实战项目学习Vue。...

1、英飞凌-AURIX-TC297简介
目录 TC297简介TC297特点:系统优势最具创新性的安全应用场景 printf("欢迎关注公众号:Kevin的学习站/车载嵌入式探索者,博主建立了一个车规级开发交流群, 感兴趣的朋友可以关注公众号,加个人WX:_kevin…...

Android 音频框架 基于android 12
文章目录 前言音频服务audioserver音频数据链路hal 提供什么样的作用 前言 Android 的音频是一个相当复杂的部分。从应用到框架、hal、kernel、最后到硬件,每个部分的知识点都相当的多。而android 这部分代码在版本之间改动很大、其中充斥着各种workaround的处理&a…...

项目实践:类平面抓取点计算(占位,后面补充)
文章目录 文章目录:3D视觉个人学习目录微信:dhlddxB站: Non-Stop_...

中央空调秒变智能 青岛中弘P15面板式空调网关初体验
在智能家居逐步渗透进千家万户的今天,如何将中央空调融入到智能化场景,以实现场景联动、提升家居生活的智能化和科技化程度,中弘给出了新的答案。本期智哪儿就带大家测评一下青岛中弘P15面板式空调网关,一起看看它的价值所在。 高…...

vue create -p dcloudio/uni-preset-vue my-project创建文件报错443
因为使用vue3viteuniappvant4报错,uniapp暂不支持vant4,所以所用vue2uniappvant2 下载uni-preset-vue-master 放到E:\Auniapp\uni-preset-vue-master 在终端命令行创建uniapp vue create -p E:\Auniapp\uni-preset-vue-master my-project...

本地电脑搭建Plex私人影音云盘教程,内网穿透实现远程访问
文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语6 总结 1.前言 用手机或者平板电脑看视频,已经算是生活中稀松平常的场景了,特…...

CI/CD 持续集成 持续交付
CI(Continuous integration)持续集成 参考:https://www.jianshu.com/p/2132949ff84a 持续集成是指多名开发者在开发不同功能代码的过程当中,可以频繁的将代码行合并到一起并切相互不影响工作。 持续集成的目的,是让…...

《Go 语言第一课》课程学习笔记(十一)
控制结构 if 的“快乐路径”原则 针对程序的分支结构,Go 提供了 if 和 switch-case 两种语句形式;而针对循环结构,Go 只保留了 for 这一种循环语句形式。 if 语句 if 语句是 Go 语言中提供的一种分支控制结构,它也是 Go 中最常…...
C++--完全背包问题
1.【模板】完全背包_牛客题霸_牛客网 你有一个背包,最多能容纳的体积是V。 现在有n种物品,每种物品有任意多个,第i种物品的体积为vivi ,价值为wiwi。 (1)求这个背包至多能装多大价值的物品? ࿰…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...