热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

6种JavaScript技术帮助您编写更简洁的代码

英文|https:betterprogramming.pub6-javascript-techniques-to-help-you-write-cleaner-code-a5f86

41fb692bc1ec9360729b64a6ce06a458.png

英文 | https://betterprogramming.pub/6-Javascript-techniques-to-help-you-write-cleaner-code-a5f867a6c750

翻译 | 杨小爱

Javascript 灵活而强大。但是,有时可能会很棘手。在 Javascript 不断演进并带来新挑战的同时,我们在日常工作中也反复遇到类似的问题。

在本文中,我们将分享6个可以帮助您编写干净且可维护的 Javascript 代码的小技巧。

现在,我们就开始吧。

1、同时或顺序执行多个异步Promise

Javascript 默认是同步的。为了处理异步代码,一种常见的方法是使用 Promise。与可能导致回调地狱的回调相比,Promise 提供了一种更好的方法来处理多个异步请求。

同时处理多个承诺

Javascript 提供了 Promise.all() 方法来处理并发请求。

// simulate async operation
function fetchMockData(name, timeToWait = 2000) {return new Promise((resolve, reject) => {setTimeout(() => {resolve({ name: name });}, timeToWait);});
}
const allPromises = [fetchMockData('John'), fetchMockData('Peter')];
Promise.all(allPromises).then((results) => {const [first, second] = results;console.log(first, second);}).catch((err) => {console.log(err);});

顺序处理多个承诺

当您需要一个接一个地执行多个异步请求时,可能会有点棘手。您的第一直觉可能是使用 forEach 或 map,但它们没有按预期工作。承诺不会等到它完成才开始下一个。

不使用第 3 方库,最好的方法是使用 reduce 方法。

const allPromises = [fetchMockData('John', 4000), fetchMockData('Peter')];allPromises.reduce(async (p, curr) => {await p;return curr.then((result) => {console.log('result:', result);return curr;});
}, Promise.resolve());

在上面的reduce 方法中,我们返回一个promise,它在每次迭代中解析为另一个promise。结果是一系列承诺,使异步操作一个接一个地执行。

如输出所示,虽然,我将第一个 Promise 的超时设置为 4 秒,第二个 Promise 的默认值为 2 秒,但第一个 Promise 在第二个之前先解决。

c71c2a04eca8a4c5b2d2f93c7f5f762f.png

尽管reduce 本身是同步的,但它允许我们将promise 返回给累加器,这样可以使解决方案运行良好。

2、使用 console.time 解决性能问题

有时,我们需要调试 Javascript 函数来分析性能。开箱即用的 console.time 方法可以帮助我们测量执行时间。

控制台对象提供 time() 和 timeEnd() 方法。

首先,我们使用唯一的字符串标签调用 console.time() 方法,它启动一个计时器来跟踪代码执行的持续时间。

然后,我们运行要测量的函数。

最后,我们使用相同的标签调用 console.timeEnd() ,持续时间将在浏览器控制台中打印出来。

如果需要调试成多步骤的代码,可以启动多个定时器,用单独的定时器测量不同的步骤,以获得更清晰的图景。

这是一个带有两个计时器的示例:

function accumlateNumbers() {let output &#61; 0; for (var i &#61; 1; i <&#61; 4000000; i&#43;&#43;) {output &#43;&#61; i;}return output;
}function callAccumlateFunction() {const timeLabel &#61; &#39;Time taken accumlateNumbers&#39;;console.time(timeLabel);const output &#61; accumlateNumbers();console.timeEnd(timeLabel);
}const timeLabel2 &#61; &#39;Time taken by callAccumlateFunction&#39;;
console.time(timeLabel2);
console.log(callAccumlateFunction());
console.timeEnd(timeLabel2);

输出是&#xff1a;

Time taken accumlateNumbers: 9.656005859375 ms
Time taken by callAccumlateFunction: 10.19677734375 ms

请注意&#xff0c;console.time 不适合需要高精度的时间测量。

3、 使用选项对象模式来处理传递给函数的多个参数

options 对象模式是为了解决向函数传递多个参数的问题。

使用将参数列表传递给函数的正常方式&#xff0c;我们需要注意参数的顺序。不正确的顺序会造成难以检测的缺陷。

function createUser(lastName, firstName, jobTitle, role){};
// we try to create a admin user
createUser(“John”,”Paul”,"admin", ”Manager”);

使用选项对象模式&#xff0c;我们只需要传递一个参数&#xff0c;它是一个包含所有参数选项的命名键的对象。

function createUser({lastName, firstName, jobTitle, role}){};
const user &#61; {firstName: &#39;John&#39;, lastName: &#39;John&#39;, jobTitle:&#39;Manager&#39;, role: &#39;Admin&#39;
};
createUser(user);

如上面的代码片段所示&#xff0c;不仅我们不需要担心参数的顺序&#xff0c;而且带有选项对象模式的命名参数使代码更易于阅读。

选项对象模式通常用于四个或更多参数的情况。

4、组合多个函数

函数组合是将多个函数组合在一起&#xff0c;并将每个函数应用于前一个函数的结果的方法。在正确的用例中使用时&#xff0c;函数组合可以使您的代码简洁优雅。

这是一个简单的例子&#xff1a;

const applyFixDiscount&#61; (x) &#61;> x - 20
const applyVipOffer &#61; (x) &#61;> x / 2
const getDiscountedPrice &#61; (x) &#61;> applyVipOffer(applyFixDiscount(x))
console.log(getDiscountedPrice(100)) // 40

上述方法有效&#xff0c;但当更多功能组合在一起时将难以阅读。更好的方法是使用下面的 compose 函数。

compose &#61;(...fns) &#61;>(initialVal) &#61;>fns.reduceRight((val, fn) &#61;> fn(val), initialVal);const getDiscountedPrice &#61; compose(applyVipOffer, applyFixDiscount);
console.log(&#39;price:&#39;, getDiscountedPrice2(100)) // 40

通用的 compose 函数可以将多个函数作为输入并一一调用。因此我们称 compose 为高阶函数。高阶函数的优势在于它能够以非常有表现力的方式组合多个操作。

请注意&#xff0c;它使用了 reduceRight&#xff0c;这意味着函数是从右到左执行的。另一种方法是下面的管道方法。它使用reduce&#xff0c;所以顺序是从左到右。

pipe &#61; (...fns) &#61;> (initialVal) &#61;> fns.reduce((val, fn) &#61;> fn(val), initialVal);const getDiscountedPrice &#61; pipe(applyFixDiscount, applyVipOffer);

应用函数组合鼓励开发人员将程序分解为更小的部分&#xff0c;并将动作或行为抽象为函数。它让你首先考虑输入和输出&#xff0c;而不是专注于实现细节。

结果将是更具可读性、可测试性和可重用性的代码。

在实际项目中&#xff0c;函数组合的正确用例包括数据处理、复杂规则计算、工作流操作等。

5、使用解构来提取数据

解构是一种将值从对象属性或数组解包到多个变量的简单而简洁的方法。

解构的基本例子是&#xff1a;

const user &#61; {name: &#39;John Paul&#39;,age: 23
};
// from object properties
const {name, age} &#61; user;
const count&#61; [&#39;one&#39;, &#39;two&#39;, &#39;three&#39;];
// array destructuring
const [first, second, third] &#61; count;

提供了一些有用的破坏功能&#xff0c;包括默认值、跳过数组元素、分配新变量名等。您可以在此处找到完整列表。

下面是一些我经常使用的实际例子。

从函数结果中析构

function getUser() {return {name: ‘John’, age: 24};
}
const {name, age} &#61; getUser(); // name&#61;&#39;John&#39;, age&#61;24

拆分数组

const [first, ...rest] &#61; [&#39;1&#39;, &#39;2&#39;, &#39;3&#39;, &#39;4&#39;];
// output: first&#61;&#39;1&#39;, rest&#61;[&#39;2&#39;, &#39;3&#39;, &#39;4&#39;]

获取数组的第一个元素

const fruits &#61; [‘apple’, ‘orange’, ‘pear’];
[first] &#61; fruits; // first&#61; &#39;apple&#39;

销毁 promise.all() 的结果

Promise.all([ promise1, promise2, promise3])
.then( results &#61;>{ const [first, second, third] &#61; results;
})

6、有效地使用数组

数组是我们大多数人每天处理的最常见的数据结构。以下是对数组操作的一些提示&#xff1a;

使用slice不变地对数组进行排序

我们经常想对一个数组进行排序并得到一个不可变的副本。不幸的是&#xff0c; .sort 会改变原始数组。使用下面的slice&#xff0c;我们可以在不影响原始数组的情况下获得一个排序数组。

const newArr &#61; arr.slice().sort()

请注意&#xff0c;slice从原始数组中返回元素的浅拷贝。如果您需要进行深度克隆&#xff0c;您可能喜欢使用不同的方法。

从数组中删除重复项

有多种方法可以从数组中删除重复项。最简单也是我最喜欢的方法是使用 Set。

Set 是在 ES6 中引入的&#xff0c;它表示一个唯一值列表。在下面的示例中&#xff0c;我们使用扩展运算符将 Set 操作的结果作为数组返回。

const arr &#61; [1,2,3,2,3,4,5];
console.log([...new Set(arr)]); // [1,2,3,4,5]

请注意 Set 方法仅适用于原始值。

从数组中过滤掉虚假值

在 Javascript 中&#xff0c;假值可以是空字符串、false、0、null、NaN 或 undefined。下面是我最喜欢的从数组中过滤掉虚假值的方法。

const arrToFilter &#61; ["user", "", 0, NaN, 9, true, undefined, "red", false];
const result &#61; mixedArr.filter(Boolean);
console.log(result); // returns ["user", 9, true, "red"]

如果您之前没有使用过它&#xff0c;您可能想知道 filter(Boolean) 是如何工作的&#xff1f;

Boolean 是一个对象包装器。在 filter(Boolean) 方法中&#xff0c;数组中的每一项都被传入并评估如下。结果为真或假&#xff0c;假值将被过滤掉。

.filter(x&#61;> Boolean(x));

使用 Array.every 和 Array.some 来简化代码

Array.every 和 Array.some 是简化代码的非常方便的方法。与其他方法如 forEach 或 reduce 相比&#xff0c;Array.every 和 Array.some 使代码更具可读性和简洁性。

const users &#61; [{ name: &#39;john&#39;, role: &#39;admin&#39; },{ name: &#39;peter&#39;, role: &#39;dev&#39; },{ name: &#39;mary&#39;, role: &#39;dev&#39; }];
const isAllDeveloperRole &#61; users.every(f &#61;> f.role &#61;&#61;&#61; &#39;dev&#39;);
const hasDeveloperRole &#61; users.some(f &#61;> f.role &#61;&#61;&#61; &#39;dev&#39;);

总结

我希望这篇文章对您有用。感谢您的阅读。

学习更多技能

请点击下方公众号

b0c0ee190a3b75fb852a3c562539b4f7.gif

6054321f3dfa29a25de23e3f979f3570.png

3b8ffb1ee758e7ef2b55a84597762118.png


推荐阅读
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 网址:https:vue.docschina.orgv2guideforms.html表单input绑定基础用法可以通过使用v-model指令,在 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
  • Python已成为全球最受欢迎的编程语言之一,然而Python程序的安全运行存在一定的风险。本文介绍了Python程序安全运行需要满足的三个条件,即系统路径上的每个条目都处于安全的位置、"主脚本"所在的目录始终位于系统路径中、若python命令使用-c和-m选项,调用程序的目录也必须是安全的。同时,文章还提出了一些预防措施,如避免将下载文件夹作为当前工作目录、使用pip所在路径而不是直接使用python命令等。对于初学Python的读者来说,这些内容将有所帮助。 ... [详细]
  • 怀疑是每次都在新建文件,具体代码如下 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
author-avatar
淋殁
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有