在任何编程语言中,代码需要根据不同的条件在给定的输入中做不同的决定和执行相应的动作。
例如,在一个游戏中,如果玩家生命点为0,游戏结束。在天气应用中,如果在早上被查看,显示一个日出图片,如果是晚上,则显示星星和月亮。在这篇文章中,我们将探索JavaScript中所谓的条件语句如何工作。
如果你使用JavaScript工作,你将写很多包含条件调用的代码。条件调用可能初学很简单,但是还有比写一对对if/else更多的东西。这里有些编写更好更清晰的条件代码的有用提示。
数组方法 Array.includes
提前退出 / 提前返回
用对象字面量或Map替代Switch语句
默认参数和解构
用 Array.every & Array.some 匹配全部/部分内容
使用可选链和空值合并
使用 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
这里,我们创建来一个动物数组,所以条件语句可以和代码的其余部分抽象分离出来。现在,如果我们想要检查任何其他动物,我们只需要添加一个新的数组项。
我们也能在这个函数作用域外部使用这个动物数组变量来在代码中的其他任意地方重用它。这是一个编写更清晰、易理解和维护的代码的方法,不是吗?
这是一个精简你的代码的非常酷的技巧。我记得当我开始专业工作时,我在第一天学习使用提前退出来编写条件。
让我们在之前的例子上添加更多的条件。用包含确定属性的对象替代简单字符串的动物。
现在的需求是:
const printAnimalDetails = animal => {
let result; // declare a variable to store the final value
// condition 1: check if animal has a value
if (animal) {
// condition 2: check if animal has a type property
if (animal.type) {
// condition 3: check if animal has a name property
if (animal.name) {
// condition 4: check if animal has a gender property
if (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 present
if (vegetable) {
// condition 2: must be one of the item from the list
if (vegetables.includes(vegetable)) {
console.log(I like ${vegetable});
// condition 3: must be large quantity
if (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'
现在,我们有:
一个普遍遵循的规则是:在非法条件匹配时提前退出。
function printVegetablesWithQuantity(vegetable, quantity) {
const vegetables = ['potato', 'cabbage', 'cauliflower', 'asparagus'];
// condition 1: throw error early
if (!vegetable) throw new Error('No vegetable from the list!');
// condition 2: must be in the list
if (vegetables.includes(vegetable)) {
console.log(I like ${vegetable});
// condition 3: must be a large quantity
if (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 early
if (!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 quantity
if (quantity >= 10) {
console.log('I have bought a large quantity');
}
}
通过倒置条件2,代码没有嵌套语句了。这种技术在我们有很多条件并且当任何特定条件不匹配时,我们想停止进一步处理的时候特别有用。
所以,总是关注更少的嵌套和提前返回,但也不要过度地使用。
让我们来看看下面的例子,我们想要基于颜色打印水果:
function printFruits(color) {
// use switch case to find fruits by color
switch (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 color
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum']
};
function printFruits(color) {
return fruitColor[color] || [];
}
另外,你也能用 Map
来实现相同的功能:
// use Map to find fruits by color
const 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);
}
当使用 JavaScript 工作时,我们总是需要检查 null/undefined
值并赋默认值,否则可能编译失败。
function printVegetablesWithQuantity(vegetable, quantity = 1) {
// if quantity has no value, assign 1
if (!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
属性。
我们能使用数组方法减少代码行。查看下面的代码,我们想要检查是否所有的水果都是红色的:
const fruits = [
{ name: 'apple', color: 'red' },
{ name: 'banana', color: 'yellow' },
{ name: 'grape', color: 'purple' }
];
function test() {
let isAllRed = true;
// condition: all fruits must be red
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 test() {
// condition: short way, all fruits must be red
const 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 red
const isAnyRed = fruits.some(f => f.color == 'red');
console.log(isAnyRed); // true
}
这有两个为编写更清晰的条件语句而即将成为 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 阶段,让我们等待它获得批准,然后我们就能无处不在地看到这难以置信的语法的使用。
让我们为了编写更清晰、易维护的代码,学习并尝试新的技巧和技术,因为在几个月后,长长的条件看起来像搬石头砸自己的脚。
本文由哈喽比特于4年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/QNXROkBmk12MvyvUy7D7Sg
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。