毫无疑问,数组是最有用和最流行的JS数据结构之一。这些索引的集合一次又一次地证明,它们仍然是各种用例的最佳选择(如果不只是它一个的话)。但是,如果没有它们完整的、极具表现力的API,数组本身就不会那么有价值。这就是今天帖子的主题!
我们将介绍一些不太为人所知的方法,以及其他一些可能很难记住的方法,这些方法是在数组API中原生包含的。有些甚至可以追溯到很久以前!在它们的帮助下,你将能够编写更简洁、更实用的代码(当然是以FP-style),有时甚至可以编写更高性能的JS代码!其中一些可能简单一些,一些可能要困难点,但是本文绝对不是针对完全初学者的!当然,如果你已经知道并记住了所有这些,花点时间来提醒自己一些细节或学习一些新技巧!需要更多内容可以搜爱创课堂,进行关注
转换
为了更好的阅读体验,我将所有列出的方法分成4组。每个组都收集至少共享一个特殊属性的方法。第一组称为“转换”。它里边的所有的方法都是将数组转换为其他形式。它们都以不可变的方式运行,在结果中返回一个新的数组,并不影响原始数组。
.filter()
我想我不需要讨论过滤数组有多有用。使用.filter()你可以做到这一点!你所要做的就是传递一个过滤函数,给定当前元素的值、索引和源数组,该函数会输出布尔值,用于指示给定元素是否应该包含在结果数组中。
.map()
.map()可能是FP定制的JS编程中最受欢迎的数组方法之一。如你所指,它使用给定的映射函数来处理(“map”)你的数组,并返回一个带有新处理过的数据的新数组。上面提到的函数提供了一个标准参数集,其中包括元素、索引和源数组参数,并且应该返回将要包含在结果中的值。因此,有了所有这些数据,你就已经具备了以你想要的方式改变你的数组所需要的所有东西.
.flat[Map]()
嵌套数组在现在是很常见的。实践证明它们在表示2D或3D数据格式时特别有用。使用这样的维度完全有可能进行更深入的研究,但是,正如我们都知道的,跟踪和访问这样的数据会变得越来越困难。ECMAScript规范的开发人员清楚地认识到了这种模式,并从最新的ES规范和始终绿色的浏览器开始,为我们引入了新的.flat()方法。它的规则很简单——它只是按指定的深度(默认为1)将嵌套数组扁平化,并有效地为你提供一个比以往任何时候都要扁平的数组!
还有另一个与数组扁平化相关的方法。我说的是. flatMap(),正如你所预料的,它是.map()和.flat()方法的完美结合。基本上,你可以像.map()那样使用这个方法——使用相同的参数集,等等,但是生成的数组稍后会被扁平化1层。很简单的。那么,这种方法可能的用例有哪些?为此,请思考一下下面的字符串处理示例。
也许这有点粗略,但我想你已经明白了。一旦你理解了这个方法是如何工作的,你肯定会发现一些你自己的用例。附注,这种方法比分别使用.map()和.flat()性能要好一点。
交互
“交互”类别将所有在源数组上运行的方法进行了分组,这些方法并不会提供一个全新的数组,而是对数组进行改变或返回完全不同类型的值。
.reverse()
当然,.reverse()方法很简单,但是不太为人所知,它的作用与其名称的含义完全相同——反转数组中元素的顺序。因此,最后的将被放在第一个。在处理不同类型的队列时,这个方法很可能会派上用场。记住,这个方法会改变源数组。
.reduce[Right]()
如果你想快速地将你的数组(“reduce”)转换为单个值,你可以使用.reduce()方法来轻松地实现。如果提供了正确的函数(所谓的缩减器),它稍后会对数组中的每个元素执行该函数,并将结果累积到一个变量中。
这个参数函数会返回一个累积值,稍后你可以用它的第一个参数来引用它。在顶峰时,该函数可以提供4个参数(按给定顺序):
累积值 (可以是字符串、数组、对象或任何其他什么);
数组的当前值会被缩减;
当前值的索引;
将被缩减的数组;
如果缩减顺序对你来说很重要,那么你应该知道你还可以使用.reduceRight()方法,它与前面的方法执行完全相同的操作,但是它是从右边开始,向前进行。
.find[Index]()
查找数组中的特定元素可能是一项艰巨的任务,除非它是第一个或最后一个元素。这里,ES6规范中添加的 .find()方法就非常有用。它只接受处理标准参数集的检查函数,并从给定数组中返回第一个匹配的值,否则返回undefined。
还有一个.findIndex()方法,与第一个方法一样,它使用匹配函数来查找值,但是返回的是索引而不是原始值。它可以与.indexOf() 或 .lastIndexOf()进行比较,也可以用来检索与提供的值匹配的第一个和最后一个值的索引,但是它的表达能力不如.findIndex()及其匹配函数。
最后一点需要注意的是——如果你使用.indexOf()只是为了检查一个值是否在给定的数组中,你可以考虑使用.includes() (ES6特性)——它返回一个布尔值,并且比它的替代方法具有更好的性能。
.every()
正如一些人所期望的那样,.every()只是在给定数组的每个元素上运行提供的函数,这里的命名可能会产生误导。相反,.every()确实在每个元素上运行一个函数,但只是为了检查它们是否遵循了我们提供的准则,并最终返回一个合法的布尔值。检查函数提供了参数的标准集合。
.copyWithin()
对于某些人来说,在单个数组的边界内复制数据可能会有点复杂和无意义。但是,由于它优越的性能(特别是对它的对手TypedArrays来说), 这个方法提供了一种快速移动数组元素的好方法! 在这里,你可以传入1到3个参数:
复制的数据将被粘贴的目标索引。由于 .copyWithin()不会改变源数组的长度,因此,源数组会被替换,旧的数据会被移除。
开始索引,标记要复制的数据的开头(默认为0,数组的起始索引)
结束索引,标记要复制的数据的末尾(不包括提供的索引)(默认为.length,即给定数组的末尾)
、
.sort()
.sort()是执行其名称所说明的操作的方法之一。在本例中,它只是对数组进行排序,你可以为它提供一个比较函数,也可以不提供。默认情况下,所有的值都会被转换成字符串,并按照UTF-16编码进行升序排序,也就是说数字从小到大,字符串按照字母表顺序。你也可以提供一个接受两个元素作为独立参数进行比较的函数。这个比较函数会返回一个数字,它将被用于以一个给定的方式对提供的值进行排序。
如果函数返回的数小于0,则作为第一个参数提供的值优先;
如果函数返回的数字等于0,则值将保持不变(规范并没有真正保证);
如果函数返回的数大于0,则作为第二个参数提供的值优先;
.some()
.some()是一个类似于.every()的方法。它检查源数组中的元素是否满足某些规则(以检查函数的形式提供),并在最后返回一个布尔值。所不同的是, .some()只需要一个元素满足测试,就返回一个正值,不像.every()那样要求每个元素都满足测试。它可以帮助你,例如检查是否至少有一个值带有给定的属性。提供的测试函数接收一个标准参数集合(元素、索引和源数组)。
迭代
令人惊讶!实际上,在数组API中,只有一个方法可以执行迭代操作。对于那些使用.map()、.reduce()和类似方法的人来说,这只是一个警告,因为这些方法只用于遍历源数组。只有一个方法适用于这个任务,因此,它应该被尊重和众所周知。
.forEach()
.forEach()会执行其名称所代表的操作——遍历源数组的每个元素。在提供一个接收标准参数集的函数的情况下,它会在给定数组的每个元素上运行该函数。
其他
除了以上所有类别之外,数组API还有更多的方法。下面是其中一些,它们肯定不太为人所知和使用,但在某些特殊情况下可能会派上用场。
.entries()
.entries()是三个返回迭代器-对象方法中的第一个。数组迭代器对象或所谓的iterable是一个简单的结构,可以通过使用for... of循环对该结构进行迭代,它还有一个单独的.next()方法,该方法在迭代时被称为底层方法。当直接调用时,它会返回一个包含value和done属性的对象,这两个属性分别指示当前值和迭代是否完成。当再次调用时,它会返回数组的下一个值,这个过程会持续到源数组的末尾,此时,done 属性将被设置为true。
.entries()方法返回的迭代器将带有以键值对(数组)的形式存在的值,其中第一个元素表示当前索引,第二个元素表示各自的值。你可以将其(稍后将讨论其他方法)与对应的对象进行比较。像Object.entries()或Object.keys() (不在原型中)这样的函数当然比它们的数组兄弟函数更受欢迎,但是它们也做类似的事情。
迭代完成后,你不能重新启动它。再次执行相同操作的惟一方法是使用相同的方法再创建一个新的iterable。
但是这种方法的用例是什么呢?.next()方法肯定会给你更多的如何迭代你的数组的控制权。而且,.entries()返回的类键值对在我们想同时访问元素的值和索引时肯定是很有用的。但是,在这些情况下,标准对象或映射(我在前一篇文章中讨论过)可能对你来说会更方便。
.keys()
前面我们已经介绍了iterable背后的所有复杂性,还里有两个类似于.entries()的方法——.keys() 和 .values()。第一个方法,顾名思义,会返回一个其值等于源数组索引(即键)的iterable。代替键值数组,它会返回表示数组元素索引的数字。
.values()
.values()方法同样会返回iterable。这一次它的值等于源数组元素的值。
.toString()
我想讨论的最后一个方法是.toString()。它存在于JS对象、函数、字符串、数字、数组和更多对象中!可能存在于每个JS对象(一切皆对象)中! 但我认为,尽管.toString()方法无处不在,但它仍然没有得到应有的关注。
从其核心来说,.toString()方法只是将一个数组转换为字符串。返回的值有一种数组元素的形式,这些元素紧密地放在一起,用逗号分隔。
但是它最大的优点是不需要被直接调用!
这样一来,每次当你的值需要转换为字符串(例如字符串常量或连接)时,你都可以调用此方法。考虑到这一点,以及你可以使用自己的实现自由地更改这个方法,在执行这些操作时,你不但可以返回自定义的字符串,还可以执行特定的操作! ✨相信我——这可以让你进行一些很有趣的操作!
数组时间!
这些是我个人挑选的一些最有趣和最有价值的数组API方法!你都知道它们吗? 我知道内置的API很容易被遗忘,从而会导致我们去寻找没有必要存在的问题的解决方案。我希望这篇文章至少能帮你解决其中的一些。