最全的数组操作方法,你造吗?

时间:2022-06-19
本文章向大家介绍最全的数组操作方法,你造吗?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在 JavaScript 中,对于数组的操作非常频繁,对应的 API 也很丰富 。ECMAScript 规范在每一版发布时,都会提供新的 API 来增强数组的操作能力,下面将详细介绍这些 API 的一些特性。


ES5 新增的 9 个API

forEach( callback, [thisArg] )

在 ES5 之前,我们可以通过 for 和 for in 两种方式来遍历数组。

ES5 引入了一个新方法 forEach,使数组遍历更加简洁,

forEach需要传递两个参数,第一个参数是回调函数,是必选参数,第二个参数是一个对象,用来改变 callback 中的 this 指向,是可选参数。

输出结果:

a 0 ['a', 'b', 'c']
b 1 ['a', 'b', 'c']
c 2 ['a', 'b', 'c']

callback 中传入了3个参数 v,i,r 分别表示当前元素、当前位置、数组对象。

再看看使用 thisArg 的例子:

输出结果:

a 0
b 1
c 2

不传 thisArgs 时,callback 中的 this 默认指向 window 对象,当传递 thisArg 时,callback 中的 this 就指向了 thisArg.

因此这个参数的目的就是为了改变回调函数中的this指向。

对于不支持 ES5 的浏览器,我们可以对 forEach 进行简单的扩展来兼容老的浏览器:


filter( callback , [thisArg] )

filter 是`过滤`的意思,所以这个方法的作用就是返回一个匹配过滤条件的新数组,其接收两个参数 callback 和 thisArg,callback也是回调函数,主要用于对元素进行条件匹配,thisArg 和 forEach中的 thisArg 作用一样,在这里就不重复了,看下面示例:

打印newArr结果 ["a", "a"]

没有filter的时候,要实现这个功能,我们事先要创建一个空的数组,把匹配到的元素再 push 进去,现在就不需要那么麻烦了,我们再看看对filter的扩展:

可以看出,filter 将过滤的结果作为一个新数组返回,即使符合条件的元素只有一个,返回的也是数组 。为了更方便的对单个元素进行查询,ES6 在数组原型上提供了 find 方法,用于从数组中查询单个符合条件的元素,和 filter 不同的是,它返回的是单个元素。

[2, 3, 5, 8, 9, 3].find(item => item == 3); // 3 

需要注意的是,find 只返回第一个匹配到的元素,如果没有匹配到,则会返回 undefined 。和 filter 一样,find 也可以传递第 2 个参数,用于设置回调函数的 this 指针 。


map( callback, [thisArg] )

map 的作用是对原数组进行加工处理后并将其作为一个新数组返回,该方法同样接收两个参数,callback 是回调函数用于对数组进行加工处理,thisArg 和上面的一样。先看一个简单的例子:

打印newArr[0] 结果:{w: 10, h: 10, area: 100}

可以看出,newArr 返回的是增加了 area 属性的对象数组。这个方法非常实用,一般情况下,当一个ajax请求返回时,我们都要对其结果集进行过滤和校验等操作,这时 map 就派上用场了。我们再看看如果对 map 进行兼容性扩展:


reduce ( callback, [initialValue] )

reduce 在这里有`减少`的意思,其作用是对数组进行归并操作,换句话说就是对数组每一个元素进行累加,最终返回所有元素之和。 回调函数 callback 接收4个参数:

previousValue - 存放的是上一次callback返回的结果,其初始值默认为数组的第一个元素。
currentValue - 是当前元素 。默认从数组的第二个元素开始。
currentIndex - 是当前元素位置 。
array - 是当前数组。

输出结果:

1 2 1
3 3 2
6 4 3

打印newArr ---> 10

reduce 除过可以传递 callback 之外,还可以传递一个参数 initialValue ,作为数组累加的基数。当传了这个参数以后,callback 中的 previousValue 初始值就被置为 initialValue,reduce 也改为从数组的第一个元素开始遍历。

输出结果:

100 1 0
101 2 1
103 3 2
106 4 3 

打印newArr ---> 110

从结果可以看出,reduce 最终返回的是: previousValue + 数组本身归并计算的结果。对 reduce 的 polyfill 实现如下:


reduceRight ( callback, [initialValue] )

和 reduce 的作用完全相同,唯一的不同是,reduceRight 是从右至左遍历数组的元素。


some ( callback, [thisArg] )

some 是`某些、一些`的意思,其作用是对数组中的每一项执行回调函数,如果该函数对任一项返回 true,则停止遍历,并返回 true 。

输出结果:

1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]

打印 result ---> true

some 检测整个数组,只要当arr中有一个元素符合条件 item>2 就停止检测和遍历,并返回 true,以表示检测到目标。这和我们在 for 循环中使用 break 语言的作用有点类似。

对于 some 的兼容性扩展如下:


every (callback, [thisArg])

every 是`每一个`的意思,其作用是对数组中的每一项执行回调函数,如果该函数对每一项都返回 true,则返回 true 。

输出结果:

1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]

打印result ---> false

当检测第3个元素时,item<3 为 false,停止检测,并返回 false,这说明every在检测元素时,要求每一个元素都要符合条件 item<3,如果有一个不符合就停止检测,并返回false。(你可以测试 item<5 时的运行结果,返回值一定是 true ) 。

那 every 到底有什么作用呢? 当一个 for 循环使用了 break 语句后,我们想知道 for 循环是否正常的执行完时, 我们一般会通过检测for中的索引 i==arr.length 来判断,因此every 的作用就体现在这里。

下面是对于 every 的兼容性扩展:


indexOf[searchElement, [fromIndex]]

indexOf() 用于查询数组元素对应的索引位置,可以传递两个参数,第一个参数是要匹配的元素,必须是简单数据类型。第二个参数是指定查询的起始位置。

// 默认从索引0的位置开始
[1, 2, 3, 5, 2].indexOf(2);// 1
// 指定从索引3的位置开始
[1, 2, 3, 5, 2].indexOf(2, 3);// 4

ndexOf() 返回的是元素在数组中的位置 。如果只想知道数组中是否存在某个元素,而不关心元素的位置,也可以使用 ES6 提供的 includes() 方法来判断。

let a = [1, 2, 3];
a.includes(1);// true
a.includes(1, 1);// false

includes() 也是数组原型上的方法, 和 indexOf() 的传参是一样的。

需要注意的是,indexOf() 适用于数组元素是简单类型的情况,而无法检索对象数组的元素位置。

let arr = [{c: 1}, {c: 2}];// 对象数组
arr.indexOf({c: 1});// -1

对于这个问题,可以使用 forEach() 来遍历数组,当找到符合条件的元素时,就可以获取到对应的数组下标,而在 ES6 中,可以使用 findIndex() 达到同样的目的。

findIndex() 也是用于查询数组元素的位置,和 indexOf() 不同的是,它可以检索对象数组的元素位置,但需要通过回调函数来指定匹配的元素。

//简单数组
[1, 2, 3, 5].findIndex(item => item == 3);// 2
//对象数组
[{id: 1}, {id: 3}, {id: 5}].findIndex(item => item.id == 3);// 1

lastIndexOf[searchElement, [fromIndex]]

和 indexOf() 的作用完全相同,唯一的不同是,lastIndexOf() 是从右至左检索数组元素。