「译」掌握了这些小技巧,让条件语句变得更优雅

点击上方“前端小苑”,选择“置顶公众号”

精品技术文章,热门资讯第一时间送达

介绍

如果你像我一样乐于见到整洁的代码,那么你会尽可能地减少代码中的条件语句。通常情况下,面向对象编程让我们得以避免条件式,并代之以继承和多态。我认为我们应当尽可能地遵循这些原则。

正如我在另一篇文章 JavaScript 整洁代码的最佳实践里提到的,你写的代码不单单是给机器看的,还是给“未来的自己”以及“其他人”看的。

从另一方面来说,由于各式各样的原因,可能我们的代码最终还是会有条件式。也许是修复 bug 的时间很紧,也许是不使用条件语句会对我们的代码库造成大的改动,等等。本文将会解决这些问题,同时帮助你组织所用的条件语句。

技巧

以下是关于如何构造 if...else 语句以及如何用更少的代码实现更多功能的技巧。阅读愉快!

1. 要事第一。小细节,但很重要

不要使用否定条件式(这可能会让人感到疑惑)。同时,使用条件式简写来表示 boolean 值。这个无须再强调了,尤其是否定条件式,这不符合正常的思维方式。

-不好的-:

const isEmailNotVerified = (email) => {    // 实现

}

if (!isEmailNotVerified(email)) {    // 做一些事...

}

if (isVerified === true) {    // 做一些事...

}

*好的*:

const isEmailVerified = (email) => {    // 实现

}

if (isEmailVerified(email)) {    // 做一些事...

}

if (isVerified) {    // 做一些事...

}

现在,理清了上面的事情后,我们就可以开始了。

2. 对于多个条件,使用 Array.includes

假设我们想要在函数中检查汽车模型是 renault 还是 peugeot。那么代码可能是这样的:

const checkCarModel = (model) => {    if (model === 'renault' || model === 'peugeot') {        console.log('model valid');    }

}

checkCarModel('renault'); // 输出 'model valid'

考虑到我们只有两个模型,这么做似乎也还能接受,但如果我们还想要检查另一个或者是几个模型呢?如果我们增加更多 or 语句,那么代码将变得难以维护,且不够整洁。为了让它更加简洁,我们可以像这样重写函数:

const checkCarModel = (model) => {    if (['peugeot', 'renault'].includes(model)) {        console.log('model valid');    }

}

checkCarModel('renault'); // 输出 'model valid'

上面的代码看起来已经很漂亮了。为了更进一步改善它,我们可以创建一个变量来存放汽车模型:

const checkCarModel = (model) => {    const models = ['peugeot', 'renault'];    if (models.includes(model)) {        console.log('model valid');    }

}

checkCarModel('renault'); // 输出 'model valid'

现在,如果我们想要检查更多模型,只需要添加一个新的数组元素即可。此外,如果它很重要的话,我们还可以将 models 变量定义在函数作用域外,并在需要的地方重用。这种方式可以让我们集中管理,并使维护变得轻而易举,因为我们只需在代码中更改一个位置。

3. 匹配所有条件,使用 Array.every 或者 Array.find

在本例中,我们想要检查每个汽车模型是否都是传入函数的那一个。为了以更加命令式的方式实现,我们会这么做:

const cars = [    {model: 'renault',year: 1956},    {model: 'peugeot',year: 1968},    {model: 'ford',year: 1977}

];

const checkEveryModel = (model) => {    let isValid = true;    for (let car of cars) {        if (!isValid) {            break;        }        isValid = car.model === model;    }    return isValid;

}

console.log(checkEveryModel('renault')); // 输出 false

如果你更喜欢以命令式的风格行事,上面的代码或许还不错。另一方面,如果你不关心其背后发生了什么,那么你可以重写上面的函数并使用 Array.every 或者 Array.find 来达到相同的结果。

const checkEveryModel = (model) => {    return cars.every(car => car.model === model);

}

console.log(checkEveryModel('renault')); // 输出 false

通过使用 Array.find 并做轻微的调整,我们可以达到相同的结果。两者的表现是一致的,因为两个函数都为数组中的每一个元素执行了回调,并且在找到一个 falsy 项时立即返回 false

const checkEveryModel = (model) => {    return cars.find(car => car.model !== model) === undefined

}

console.log(checkEveryModel('renault')); // 输出 false

4. 匹配部分条件,使用 Array.some

Array.every 匹配所有条件,这个方法则可以轻松地检查我们的数组是否包含某一个或某几个元素。为此,我们需要提供一个回调并基于条件返回一个布尔值。

我们可以通过编写一个类似的 for...loop 语句来实现相同的结果,就像之前写的一样。但幸运的是,有很酷的 JavaScript 函数可以来帮助我们完成这件事。

const cars = [    {model: 'renault',year: 1956},    {model: 'peugeot',year: 1968},    {model: 'ford',year: 1977}

];

const checkForAnyModel = (model) => {    return cars.some(car => car.model === model);

}

console.log(checkForAnyModel('renault')); // 输出 true

5. 提前返回而不是使用 if...else 分支

当我还是学生的时候,就有人教过我:一个函数应该只有一个返回语句,并且只从一个地方返回。如果细心处理,这个方法倒也还好。我这么说也就意味着,我们应该意识到它在某些情况下可能会引起条件式嵌套地狱。如果不受控制,多个分支和 if...else 嵌套将会让我们感到很痛苦。

另一方面,如果代码库很大且包含很多行代码,位于深层的一个返回语句可能会带来问题。现在我们都实行关注点分离和 SOLID 原则,因此,代码行过多这种情况挺罕见的。

举例来解释这个问题。假设我们想要显示所给车辆的模型和生产年份:

const checkModel = (car) => {    let result; // 首先,定义一个 result 变量    // 检查是否有车    if (car) {        // 检查是否有车的模型        if (car.model) {            // 检查是否有车的年份            if (car.year) {                result = `Car model: ${car.model}; Manufacturing year: ${car.year};`;            } else {                result = 'No car year';            }        } else {            result = 'No car model'        }    } else {        result = 'No car';    }    return result; // 我们的单独的返回语句}

console.log(checkModel()); // 输出 'No car'

console.log(checkModel({year: 1988})); // 输出 'No car model'

console.log(checkModel({model: 'ford'})); // 输出 'No car year'

console.log(checkModel({model: 'ford',year: 1988})); // 输出 'Car model: ford; Manufacturing year: 1988;'

正如你所看到的,即使本例的问题很简单,上面的代码也实在太长了。可以想象一下,如果我们有更加复杂的逻辑会发生什么事。大量的 if...else 语句。

我们可以重构上面的函数,分解成多个步骤并稍做改善。例如,使用三元操作符,包括 && 条件式等。不过,这里我直接跳到最后,向你展示借助现代 JavaScript 特性和多个返回语句,代码可以有多简洁。

const checkModel = ({model,

year} = {}) => {    if (!model && !year) return 'No car';    if (!model) return 'No car model';    if (!year) return 'No car year';    // 这里可以任意操作模型或年份    // 确保它们存在    // 无需更多检查    // doSomething(model);    // doSomethingElse(year);    return `Car model: ${model}; Manufacturing year: ${year};`;

}

console.log(checkModel()); // 输出 'No car'

console.log(checkModel({year: 1988})); // 输出 'No car model'

console.log(checkModel({model: 'ford'})); // 输出 'No car year'

console.log(checkModel({ model: 'ford',year: 1988})); // 输出 'Car model: ford; Manufacturing year: 1988;'

在重构版本中,我们包含了解构和默认参数。默认参数确保我们在传入 undefined 时有可用于解构的值。注意,如果传入 null ,函数将会抛出错误。这也是之前那个方法的优点所在,因为那个方法在传入 null的时候会输出 'No car'

对象解构确保函数只取所需。例如,如果我们在给定车辆对象中包含额外属性,则该属性在我们的函数中是无法获取的。

根据偏好,开发者会选择其中一种方式。实践中,编写的代码通常介于两者之间。很多人觉得 if...else语句更容易理解,并且有助于他们更为轻松地遵循程序流程。

6. 使用索引或者映射,而不是 switch 语句

假设我们想要基于给定的国家获取汽车模型。

const getCarsByState = (state) => {    switch (state) {        case 'usa':            return ['Ford', 'Dodge'];        case 'france':            return ['Renault', 'Peugeot'];        case 'italy':            return ['Fiat'];        default:            return [];    }

}

console.log(getCarsByState()); // 输出 []

console.log(getCarsByState('usa')); // 输出 ['Ford', 'Dodge']

console.log(getCarsByState('italy')); // 输出 ['Fiat']

上诉代码可以重构,完全去除 switch 语句。

const cars = new Map()    .set('usa', ['Ford', 'Dodge'])    .set('france', ['Renault', 'Peugeot'])    .set('italy', ['Fiat']);

const getCarsByState = (state) => {    return cars.get(state) || [];

}

console.log(getCarsByState()); // 输出 []

console.log(getCarsByState('usa')); //输出 ['Ford', 'Dodge']

console.log(getCarsByState('italy')); // 输出 ['Fiat']

或者,我们还可以为包含可用汽车列表的每个国家创建一个类,并在需要的时候使用。不过这个就是题外话了,本文的主题是关于条件句的。更恰当的修改是使用对象字面量。

const carState = {    usa: ['Ford', 'Dodge'],    france: ['Renault', 'Peugeot'],    italy: ['Fiat']

};

const getCarsByState = (state) => {    return carState[state] || [];

}

console.log(getCarsByState()); // 输出 []

console.log(getCarsByState('usa')); // 输出 ['Ford', 'Dodge']

console.log(getCarsByState('france')); // 输出 ['Renault', 'Peugeot']

7. 使用自判断链接(optional-chaining)和空合并(nullish-coalescing)

到了这一小节,我终于可以说“最后”了。在我看来,这两个功能对于 JavaScript 语言来说是非常有用的。作为一个来自 C# 世界的人,可以说我经常使用它们。

在写这篇文章的时候,这些还没有得到完全的支持。因此,对于以这种方式编写的代码,你需要使用 Babel 进行编译。你可以在自判断链接这里以及在空合并这里查阅。

自判断链接允许我们在没有显式检查中间节点是否存在的时候处理树形结构,空合并可以确保节点不存在时会有一个默认值,配合自判断链接使用会有不错的效果。

让我们用一些例子来支撑上面的结论。一开始,我们还是用以前的老方法:

const car = {    model: 'Fiesta',    manufacturer: {        name: 'Ford',        address: {            street: 'Some Street Name',            number: '5555',            state: 'USA'        }    }

}

// 获取汽车模型

const model = car && car.model || 'default model';

// 获取厂商地址

const street = car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.stree||'default street';

//请求一个不存在的属性

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

因此, 如果我们想要知道厂商是否来自 USA 并将结果打印, 那么代码是这样的:

const checkCarManufacturerState = () => {

   if (car && car.manufacturer && car.manufacturer.address && car.manufacturer.address.state === 'USA') {        console.log('Is from USA');    }

}

checkCarManufacturerState() // 输出 'Is from USA'

我无需再赘述如果对象结构更加复杂的话,代码会多么混乱了。许多库,例如 lodash,有自己的函数作为替代方案。不过这不是我们想要的,我们想要的是在原生 js 中也能做同样的事。我们来看一下新的方法:

// 获取汽车模型

const model = car ? .model ? ? 'default model';

// 获取厂商地址

const street = car ? .manufacturer ? .address ? .street ? ? 'default street';

// 检查汽车厂商是否来自 USA

const checkCarManufacturerState = () => {    if (car ? .manufacturer ? .address ? .state === 'USA') {        console.log('Is from USA');    }

}

这看起来更加漂亮和简洁,对我来说,非常符合逻辑。如果你想知道为什么应该使用 ?? 而不是 || ,只需想一想什么值会被当做 true 或者 false 从而得到意料之外的输出。

顺便说句题外话。自判断链接同样支持 DOM API,这非常酷,意味着你可以这么做:

const value = document.querySelector('input#user-name') ? .value;

译者:@chorer 作者:@Milos Protic

译文:https://chorer.github.io/2019/06/24/Trs-更好的JavaScript条件式和匹配标准技巧/

原文:https://devinduct.com/blogpost/35/tips-and-tricks-for-better-javascript-conditionals-and-match-criteria

在探索智慧旅游的新纪元中,一个集科技、创新与服务于一体的整体解决方案正悄然改变着我们的旅行方式。智慧旅游,作为智慧城市的重要分支,旨在通过新一代信息技术,如云计算、大数据、物联网等,为游客、旅游企业及政府部门提供无缝对接、高效互动的旅游体验与管理模式。这一方案不仅重新定义了旅游行业的服务标准,开启了旅游业数字化转型的新篇章。 智慧旅游的核心在于“以人为本”,它不仅仅关注技术的革新,注重游客体验的提升。从游前的行程规划、信息查询,到游中的智能导航、个性化导览,再到游后的心情分享、服务评价,智慧旅游通过构建“一云多屏”的服务平台,让游客在旅游的全过程中都能享受到便捷、个性化的服务。例如,游客可以通过手机APP轻松定制专属行程,利用智能语音导览深入了解景点背后的故事,甚至通过三维GIS地图实现虚拟漫游,提前感受目的地的魅力。这些创新服务不仅增强了游客的参与感和满意度,也让旅游变得加智能化、趣味化。 此外,智慧旅游还为旅游企业和政府部门带来了前所未有的管理变革。通过大数据分析,旅游企业能够精准把握市场动态,实现旅游产品的精准营销和个性化推荐,从而提升市场竞争力。而政府部门则能利用智慧旅游平台实现对旅游资源的科学规划和精细管理,提高监管效率和质量。例如,通过实时监控和数据分析,政府可以迅速应对旅游高峰期的客流压力,有效预防景区超载,保障游客安全。同时,智慧旅游还促进了跨行业、跨部门的数据共享与协同合作,为旅游业的可持续发展奠定了坚实基础。总之,智慧旅游以其独特的魅力和无限潜力,正引领着旅游业迈向一个加智慧、便捷、高效的新时代。
内容概要:本文详细介绍了大模型的发展现状与未来趋势,尤其聚焦于DeepSeek这一创新应用。文章首先回顾了人工智能的定义、分类及其发展历程,指出从摩尔定律到知识密度提升的转变,强调了大模型知识密度的重要性。随后,文章深入探讨了DeepSeek的发展路径及其核心价值,包括其推理模型、思维链技术的应用及局限性。此外,文章展示了DeepSeek在多个行业的应用场景,如智能客服、医疗、金融等,并分析了DeepSeek如何赋能个人发展,具体体现在公文写作、文档处理、知识搜索、论文写作等方面。最后,文章展望了大模型的发展趋势,如通用大模型与垂域大模型的协同发展,以及本地部署小模型成为主流应用渠道的趋势。 适合人群:对人工智能和大模型技术感兴趣的从业者、研究人员及希望利用DeepSeek提升工作效率的个人用户。 使用场景及目标:①了解大模型技术的最新进展和发展趋势;②掌握DeepSeek在不同领域的具体应用场景和操作方法;③学习如何通过DeepSeek提升个人在公文写作、文档处理、知识搜索、论文写作等方面的工作效率;④探索大模型在特定行业的应用潜力,如医疗、金融等领域。 其他说明:本文不仅提供了理论知识,还结合实际案例,详细介绍了DeepSeek在各个场景下的应用方式,帮助读者好地理解和应用大模型技术。同时,文章也指出了当前大模型技术面临的挑战,如模型的局限性和数据安全问题,鼓励读者关注技术的持续改进和发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值