盘点数组Array方法

盘点数组Array方法

前言

数组在js中作为一个非常重要的类型之一,在我们对数据处理,存储数据,条件渲染的时候经常会用到,所以随着ES的不断更新,数组的方法也是越来越多,也让我们使用数组对数据操作的时候,越来越简单,但是不经意间,数组的方法已经有42个之多,接下来让我们看看有哪些数组方法从出来就你还没用过的吧!

数组方法

数组方法之多,大致可以分为以改变数组本身的,不改变数组本身的(返回一个新的数组),还有就是其他对数组本身功能性作用的方法

1. ⭐改变原数组(9个)

1.1 unshift & push 塞元素

  • unshift:往数组开头塞入元素,可塞入多个
  • push:往数组末尾塞入元素,可塞入多个
1
2
3
4
5
6
7
const arr = [ 1, 2, 3, 4, 5 ]
//添加到数组的前端
arr.unshift(6) //[6,1,2,3,4,5]

const arr = [ 1, 2, 3, 4, 5 ]
//添加到数组的尾端
arr.push(6) //[1,2,3,4,5,6]

1.2 shift & pop 除去元素

  • shift:把数组开头的元素去除,并返回这个元素
  • pop:把数组末尾的元素去除,并返回这个元素
1
2
3
4
5
6
7
const arr = [ 6, 1, 2, 3, 4, 5 ]
//调用shift方法就删除了第一位
arr.shift()//[1,2,3,4,5]

const arr = [ 1, 2, 3, 4, 5, 6 ]
//调用pop方法就删除了最后一位
arr.pop()//[1,2,3,4,5]

1.3 sort 排序

用来排序数组的,并且你也可以自定义排序规则,只需要传入一个函数即可

进行对数组就地排序,不会复制或返回一个新数组,接收可选参数,一个回调函数。

有a,b两个参数:

当返回a<b时返回-1从小到大排序,升序

当返回a>b时返回1从大到小排序,降序

a==b时返回0,保持原来的排序(默认排序是将元素转换为字符串,然后按照它们的 UTF-16 码元值升序排序。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const arr = ["March", "Jan", "Feb", "Dec", 6, 2, "A", "a"];
arr.sort(function (a, b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
console.log(arr);//['A','Dec', 'Feb','Jan','March',2, 6,'a']

arr = ['sunshine_lin','sanxin_lin','digger_lin']
console.log(arr.sort())
//'digger_lin','sanxin_lin','sunshine_lin'
console.log(arr)
//'digger_lin','sanxin_lin','sunshine lin'
console.Log(arr.sort((a,b)=>b.length-a.length))//根据字符串长度排序
//'sunshine_lin','digger_lin','sanxin_lin'
console.log(arr)
//'sunshine_lin','digger_lin','sanxin_lin'

1.4 reverse 反转

用来反转数组的

1
2
3
const arr = ["March", "Jan", 6, 2, "A", "a"];
arr.reverse();
console.log(arr);//[ 'a', 'A', 2, 6, 'Jan', 'March' ]

1.5 splice 截取

通常被用来截取数组,可传入:

第一个为截取的索引位置,number类型,从哪个索引开始截取

第二个截取的个数,number类型,截取几个元素

第三个或更多实在截取位置添加的参数,截取后可塞进新的元素,任何参数

这个方法的返回结果是被截取的部分

1
2
3
4
5
6
7
8
9
10
const arr = ["March", "Jan", 6, 2, "A", "a"];
//在索引为2的位置截取一个,并在索引2的位置后添加8
arr.splice(2, 1, 8);
console.log(arr);//[ 'March', 'Jan', 8, 2, 'A', 'a' ]
//在索引处截取几个
arr.splice(4, 1);
console.log(arr);//[ 'March', 'Jan', 8, 2, 'a' ]
//截取位数不够,就将有的全部且去掉
arr.splice(2);
console.log(arr);//[ 'March', 'Jan' ]

1.6 fill 填充

用来把数组填满成自己想要的元素

对数组内容进行覆盖填充,有三个参数:

第一个为填充值,

第二个为起始位置(可选),

第三个为结束位置,不包含此索引位置(可选)。

copyWithin比较类似,只不过一个是移动数组内的元素,一个填充数组的内的元素,不会改变数组的长度。并返回这个数组。

1
2
3
4
5
6
7
8
9
10
11
12
const arr1 = ["March", "Jan", 6, 2, "A", "a"];
//将666填充到1-4不包括4索引的位置
const newArr = arr1.fill(666, 1, 4);
console.log(newArr);//[ 'March', 666, 666, 666, 'A', 'a' ]

arr = ['sunshine_lin','sanxin_lin','digger_lin']
console.log(arr.fill(0))
//[0,0,0]
console.log(arr)
//[0,0,0]
console.log(new Array(5).fill('哈哈哈哈哈哈')
//['哈哈哈哈哈哈','哈哈哈哈哈哈','哈哈哈哈哈哈','哈哈哈哈哈哈','哈哈哈哈哈哈']

1.7 copyWithinArr 复制替换

有点类似于 splice,不过也有些不同,copyWithinArr 可以把某一个索引的元素去除,并拿数组本身的元素剪切复制进去这个索引的位置

copyWithin是一种移动数组数据的高性能方法,copyWithin() 方法是通用的。它只期望 this 值具有 length 属性和整数键属性。虽然字符串也是类似数组的,但这种方法不适用于它们,因为字符串是不可变的。

copyWithin不会改变数组的长度,只会修改内容,它接收三个参数:

第一个为复制到的目标位置(索引值),

第二个是复制的起始位置(可选),如果为负数,则相当于从后往前数,

第三个为结束位置,不包含此索引的位置(可选),

结束位置大于起始位置,同为正或同为负,否者方法无效。并返回这个原数组。

起始位置间隔大于1,则是剪切

起始位置间隔等于1,则是复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//起始位置间隔大于1,则是剪切
const arr1 = ["March", "Jan", 6, 2, "A", "a"];
//从索引为3的位置开始复制,到索引为5的位置,但不包含5,从索引为1的位置剪切粘贴并覆盖
const newArr = arr1.copyWithin(1, 3, 5);
console.log(arr1,newArr);//[ 'March', 2, 'A', 2, 'A', 'a' ] [ 'March', 2, 'A', 2, 'A', 'a' ]

//起始位置间隔等于1,则是复制
//为负数时从后往前数-2从A的位置到-1不包括-1的位置,也就是将A赋值并覆盖到了索引为0的位置
const newArr = arr1.copyWithin(0, -2, -1);
console.log(newArr);//[ 'A', 'Jan', 6, 2, 'A', 'a' ]
//从索引为1的位置开始复制,到索引为2的位置,但不包含2,从索引为0的位置复制粘贴并覆盖
const newArr = arr1.copyWithin(0, 1, 2);
console.log(newArr);//[ "Jan", "Jan", 6, 2, "A", "a" ]

//这种结束索引位置在开始索引位置之前的都不生效
const newArr = arr1.copyWithin(0, -2, 2);
const newArr = arr1.copyWithin(0, -2, -4);
console.log(newArr);//[ 'March', 'Jan', 6, 2, 'A', 'a' ]

2. 不变原数组(30个)

2.1 ⭐forEach 循环遍历

通常用来遍历,其实跟 for 的作用差不多,不过 for 支持 await 排队且 for 能终止和跳过某次步骤,forEach 不支持

1
2
3
4
5
6
7
8
9
10
arr = ['sunshine_lin','sanxin_lin','digger_lin']
arr.forEach((item,index,source)=>{
console.log(item,index,source)
//item,数组第n项
//index,数组第n项索引
//source,数组本身
})
//sunshine_lin 0 'sunshine_lin','sanxin_lin','digger_lin'
//sanxin_lin 1 'sunshine_lin','sanxin_lin','digger_lin'
//digger_lin 2 'sunshine_lin','sanxin_lin','digger_lin'

2.2 ⭐map 处理元素返回新数组

把数组的每一项都通过自定义规则去修改,并返回成一个新的数组

map方法只是单纯的返回一个新数组,可以是处理后的,也可以是原数组,接收一个回调函数,回调函数有三个参数

第一个是当前遍历的元素,

第二个为当前索引,

第三个是数组本身

需要一个返回值,从map内部处理过后,回调函数的返回值返回一个新数组

1
2
3
4
5
6
7
8
9
10
11
const arr = ["March", "Jan", 6, 2, "A", "a"];
//返回一个number的数组,不是number类型的就返回它们的字段长度
const newArr = arr.map((item, index) => (typeof item === "number" ? item : item.length);
console.log(newArr);//[ 5, 3, 6, 2, 1, 1 ]

arr = ['sunshine_lin','sanxin_lin','digger_lin']
const mapArr = arr.map(item =>{
return`${item}-是我`
})
console.log(mapArr)
//['sunshine._Lin-是我','sanxin_lin--是我','digger_lin-是我']

2.3 ⭐filter 过滤

用来过滤的,接收一个过滤函数,返回 假值 的元素会被过滤掉,返回 真值 的则会被保留

需要一定条件返回对应的数据,接收一个回调函数,有回调函数有三个参数,

第一个是当前遍历的元素,

第二个为当前索引,

第三个是数组本身

需要一个返回值,filter方法会根据符合这个返回值条件的数据返回一个新数组

1
2
3
4
5
6
7
8
9
10
11
12
const arr = ["March", "Jan", 6, 2, "A", "a"];
//这里是一个简单的例子,返回类型为string的元素
const newArr = arr.filter((item, index) => typeof item === "string");
console.log(newArr);//[ 'March', 'Jan', 'A', 'a' ]

arr = ['sunshine_lin','sanxin_.lin','digger_.lin','三心哥']
const filterArr1 = arr.filter((item=>item==='三心哥'))
console.log(filterArr1)
//['三心哥']
const filterArr2 = arr.filter((item =item.includes('lin')))
console.log(filterArr2)
//'digger_lin','sanxin_lin','sunshine_lin'

2.4 ⭐reduce 累积计算

通常会用来:

  • 根据数组每一项计算总数
  • 根据数组每一项计算出一个Map

reduce是一个功能非常强大的方法,但平常很少使用,因为他的功能他的方法都可以实现,它也能实现其他的一些方法,有时候合理的使用reduce会大大减少代码量。接收两个参数:

第一个为回调函数,回调函数有四个参数:

  • 参数1 为上一次回调函数return的结果,首次默认为第二个参数值,如果没有第二个参数值,则默认当前数组下标为0的参数,
  • 参数2 为当前元素,
  • 参数3 为当前索引值,
  • 参数4 为数组本身

第二个参数指定一个默认值,可选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//使用reduce实现filter方法
const arr = ["March", "Jan", 6, 2, "A", "a"];
//定义第二个参数的默认值为一个数组
const newArr = arr.reduce((acc, cur, index) => {
typeof cur === "string" && acc.push(cur);
return acc;
}, []);
console.log(newArr);//[ 'March', 'Jan', 'A', 'a' ]

//使用reduce实现数字的求和
//第二个参数默认定义0 number类型
const newArr = arr.reduce((acc, cur, index) => {
typeof cur === "number" && (acc += cur);
return acc;
}, 0);
console.log(newArr);//8

//计算所有字符串的总长度
arr ['sunshine_lin','sanxin_lin','digger_lin']
const totalLength = arr.reduce((pre,next)=>{
const _pre = pre + next.length
return _pre
},0)
console.log(totalLength)//32

//拼接所有字符串
const totalstr1 arr.reduce((pre,next)=>{
const _pre = `${pre}-${next}`
return _pre
},'')
console.log(totalstr1)
//-sunshine_lin-sanxin_lin-digger_lin

2.5 reduceRight 累积计算

作用跟 reduce 一模一样,只不过 reduceRight 是从后往前去遍历

这个是reduce的右边开始一种写法,运算时会从右向左执行,参数与使用方法和reduce一致。适用于当你想对一个数组进行反转加过滤等操作的时候,这个方法就完全突出了他的便携

1
2
3
4
5
6
7
const arr = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr.reduceRight((acc, cur, index) => {
typeof cur === "string" && acc.push(cur);
return acc;
}, []);
//这里打印之后可以看出,毕竟过滤了非字符串的参数,还将数组反转了
console.log(newArr);//[ 'a', 'A', 'Jan', 'March' ]

2.6 ⭐slice 截取

用来截取数组的,第一个参数是起始索引,第二个参数是终止索引,但是不会截取终止索引的元素

可以对一个数组进行浅拷贝,接收两个参数:

第一个为截取的初始位置,

第二个为终止位置(不包括此索引值),

如果只填一个参数则从当前索引值截取到最后一位

1
2
3
4
5
6
const arr = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr.slice(0, 3);
console.log(newArr);//[ 'March', 'Jan', 6 ]

const newArr = arr.slice(3);
console.log(newArr);//[ 2, 'A', 'a' ]

2.7 ⭐every 所有必须真

传入一个计算函数,需要所有元素的计算结果都返回 真值,最终方法才会返回 true,只要有一个 假值,那么最终会返回 false

every用于所有元素是否都能通过测试,返回一个布尔值,只有当所有元素都通过了测试,才会返回true

接收一个回调函数,回调函数有三个形参:

第一个为当前元素,

第二个为当前索引,

第三个为数组本身,

另外,当数组为空的时候使用every,条件不论是怎么样的,都会返回true(这种情况属于无条件正确,因为空集的所有元素都符合给定的条件。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const arr = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr.every((item) => typeof item === "string");
//并不是所有的元素都符合条件 所以返回false
console.log(newArr);//false
//只要是数组是空数组,后面的条件不管跟什么返回的永远为true
console.log([].every((item) => item > 10));//true

arr = ['sunshine_lin','sanxin_lin','digger_lin']
//判断是否每个字符串都包含lin
const isEvery1 = arr.every(item =item.includes('lin'))
console.log(isEvery1)//true
//判断是否每个字符串都包含sunshine
const isEvery2 = arr.every(item =item.includes('sunshine'))
console.log(isEvery2)//false

2.8 ⭐some 至少一个真

传入一个计算函数,至少要有一个元素的计算结果返回 真值,最终方法才会返回 true,如果所有都返回 假值,那么最终会返回 false

some用于数组中参数其中一个或多个通过了测试,返回一个布尔值,如果有一个或以上通过测试就返回true,一个都没通过返回false,

接收一个回调函数,有三个形参:

第一个为当前元素,

第二个为当前索引,

第三个为数组本身

另外,当数组为空时使用some,不论判断条件如何,都会返回false,并且他不会改变数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const arr = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr.some((item) => typeof item === "string");
//其中一个或以上的元素符合条件就返回true
console.log(newArr);//true
//只要是数组是空数组,后面的条件不管跟什么返回的永远为false
console.log([].some((item) => item==undefined));//false


arr = ['sunshine_lin','sanxin_lin','digger_lin']
//判断是否至少有一个字符串包含sunshine
const isSome1 = arr.some(item =>item.includes('sunshine'))
console.log(isSome1)/true
//判断是否至少有一个字符串包含xx×
const isSome2 = arr.some(item =>item.includes('xxx'))
console.log(isSome2)//false

2.9 ⭐concat 拼接

用来拼接两个数组,并返回拼接后的数组

需要两个或以上的数组合并的时候就可以使用concat快速合并,当然在ES6之后大多都使用扩展运算符进行数组合并了,此方法接收一个或以上得任意类型参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const arr1 = ["March", "Jan"];
const arr2 = [6, 2, "A", "a"];
const arr3 = {
name: "Tom",
age: 18,
sex: "男",
};
//如果参数是数组则会合并
const newArr = arr1.concat(arr2);
console.log(newArr);//[ 'March', 'Jan', 6, 2, 'A', 'a' ]
//一个以上的参数 如果是值类型 则会直接添加到数组得最后面
const newArr = arr1.concat(arr2,'Tom');
console.log(newArr);//[ 'March', 'Jan', 6, 2, 'A', 'a','Tom' ]
//一个以上的参数,为一个对象类型,会直接添加到对象中
const newArr = arr1.concat(arr2,arr3);
console.log(newArr);
//[ 'March', 'Jan', 6, 2, 'A', 'a', { name: 'Tom', age: 18, sex: '男' } ]

2.10⭐ join 拼接分隔符转字符串

用的频率很高的一个方法,传入一个分隔符,把数组转成一个字符串

join用于将数组转换成字符串的方法,接收一个参数(可以为任意类型,但引用类型则会默认转换成[object Object]等),为数组元素转换成字符串的间隔符,不传参数默认以 ‘,’号隔开

1
2
3
4
5
6
7
8
9
10
const arr = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr.join();
console.log(newArr);//March,Jan,6,2,A,a
//可以是number类型
const newArr = arr.join(3);
console.log(newArr);//March3Jan36323A3a
//也可以是引用类型,但会自动转换
const newArr = arr.join({ id: 1 });
console.log(newArr);
//March[object Object]Jan[object Object]6[object Object]2[object Object]A[object Object]a

2.11 ⭐flat 扁平

用来把数组扁平化,传入一个数字,可以控制需要扁平多少层,如果传入 Infinity ,则会完全扁平化

通常在扁平化数组的时候都要使用递归函数,flat方法避免了页面中写递归函数造成大量的代码冗余,flat本身也是使用递归方法来达到数组扁平化的,接收一个number类型的参数,参数是几就可以扁平几层,在不确定有几维数组的情况下,参数为Infinity(无限大),可以扁平任意层次的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
arr=[['sunshine_lin',['三心小子',['三心弟']]],'sanxin_lin','digger._Lin']
const flatArr1 = arr.flat(1)
//扁平化掉一层
console.log(flatArr1)
//['sunshine._lin',['三心小子',['三心弟']],'sanxin_lin','digger._lin']
const flatArr2 = arr.flat(2)
//扁平化掉两层
console.log(flatArr2)
//['sunshine._lin','三心小子',['三心弟'],'sanxin_lin','digger._lin']
//完全铺平
const flatArrAll = arr.flat(Infinity)
console.log(flatArrAll)
//['sunshine_lin','三心小子','三心弟','sanxin_lin','digger._lin']

2.12 flatMap 扁平

也是做扁平化的,传入一个函数,函数返回的结果如果是一个数组,最终计算出来的的最终结果中,这个数组会被拍平,这个方法应该很少人用

flatMap与map相似,都是接收一个回调函数,进行处理后返回一个数组,但有一处差别就是flatMap可以对数组进行一层扁平化(仅数组)

1
2
3
4
5
6
7
8
9
10
11
12
const arr1 = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr1.flatMap((item, index) => {
return [item, index];
});
//可以看出本应该是双层数组的,却被扁平化了
console.log(newArr);//['March', 0,'Jan', 1,6,2,2,3,'A',4,'a', 5]

const newArr = arr1.flatMap((item, index) => {
return [[item, index]];
});
//仅只能扁平化一层
console.log(newArr);//[[ 'March', 0 ],[ 'Jan', 1 ], [ 6, 2 ], [ 2, 3 ],[ 'A', 4 ],[ 'a', 5 ]]

2.13 ⭐indexOf & lastIndexOf 查找索引

传入一个数组元素,能查出这个元素在数组中的第一个索引,如果查不到则返回 -1

注意:这两个方法查不了 NaN 的索引

indexOf:从前往后查

写法和includes类似,有两个参数第一个是要找的值,第二个为开始索引,indexOf会在查找到第一个符合条件的参数跳出循环并返回索引,没找到则返回-1

lastIndexOf:从后往前查

与indexOf一致,只不过是返回最后的索引位置,也可以理解为他是从数组的右边开始往左找元素,并返回第一个找到的元素的索引,没找到则返回-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//indexOf
const arr = ["March", "Jan", 6, 2, "A", 6, "a"];
const newArr = arr.indexOf(6);
//返回索引值
console.log(newArr);//2

//查找6,从索引为3的位置开始找
const newArr = arr.indexOf(63);
console.log(newArr);//5


//lastIndexOf
//所有的结果恰恰与indexOf反过来了
const arr = ["March", "Jan", 6, 2, "A", 6, "a"];
const newArr = arr.lastIndexOf(6);
//返回索引值
console.log(newArr);//5

//查找6,从索引为3的位置开始找
const newArr = arr.lastIndexOf(63);
console.log(newArr);//2

2.14 ⭐includes 包含

传入一个数组元素,查出这个元素是否存在这个数组中,返回一个布尔值

注意:includes 可以查出数组是否包含 NaN

在数组中查抄某一个值,返回一个布尔值,有两个参数:

第一个你要查找的值,

第二个从哪个索引位置开始找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const arr = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr.includes(6);
console.log(newArr);//true

//也可以利用这一特性简化判断条件
let name='a'
//name是一个变量,可能有很多种可能,判断条件中就会非常冗余
if ( name === 'a' || name === 'A' || name === 6...) {
//...
}
//可以改成这种,看着也非常明了简便
if (['a',"A",6,...].includes(name)) {
//...
}

2.15 ⭐find & findLast 寻找元素

传入一个计算函数,根据这个计算函数的返回结果,查出数组中第一个计算返回真值的元素

find:从前往后查

find查找符合条件的的一个元素并返回那个元素本身,没有则返回undefined

接收一个回调函数,回调函数有三个形参:

  • 第一个当前元素,
  • 第二个当前索引,
  • 第三个数组本身

findLast:从后往前查

此方法兼容性不好,暂时不推荐使用,node版本需要18.0.0以上find使用方法一致,findLast从右向左查找符合条件的的一个元素,并返回那个元素,没有则返回undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//find:从前往后查
const arr = ["March", "Jan", 6, 2, "A", 6, "a"];
const newArr = arr.find((item, index) => {
return item.length > index;
});
//只会返回符合条件的第一个值
console.log(newArr);//March

//也可以用在数组对象上
const arr = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }];
const newArr = arr.find((item, index) => {
return item.id > index;
});
//返回对象元素本身
console.log(newArr);//{ id: 1 }


//findLast:从后往前查
const arr = ["March", "Jan", 6, 2, "A", 6, "a"];
const newArr = arr.findLast((item, index) => {
return item.length > index;
});
//返回Jan,从右向左第一个符合条件的就是Jan,索引值是不变的,例如arr数组,遍历的时候索引值是6、5、4、3、2、1、0
console.log(newArr);//Jan

//也可以用在数组对象上
const arr = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }];
const newArr = arr.findLast((item, index) => {
return item.id > index;
});
//返回第一个符合条件的对象元素本身
console.log(newArr);//{ id: 5 }

2.16 findIndex & findLastIndex 寻找索引

传入一个计算函数,根据这个计算函数的返回结果,查出数组中第一个计算返回真值的元素的索引

findIndex:从前往后查

find使用方法一致,findIndex查找符合条件的的一个元素并返回那个元素的索引值,没有则返回-1

接收一个回调函数,回调函数有三个形参:

  • 第一个当前元素,
  • 第二个当前索引,
  • 第三个数组本身

findLastIndex:从后往前查

此方法兼容性不好,暂时不推荐使用,node版本需要18.0.0以上findLast使用方法一致,findLastIndex从右向左查找符合条件的的一个元素,并返回那个元素的索引值,没有则返回-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//findIndex:从前往后查
const arr = ["March", "Jan", 6, 2, "A", 6, "a"];
const newArr = arr.findIndex((item, index) => {
return item.length > index;
});
//只会返回符合条件的第一个索引
console.log(newArr);//0

//也可以用在数组对象上
const arr = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }];
const newArr = arr.findIndex((item, index) => {
return item.id > index;
});
//返回对象元素所在位置的索引
console.log(newArr);//0


//findLastIndex:从后往前查
const arr = ["March", "Jan", 6, 2, "A", 6, "a"];
const newArr = arr.findLastIndex((item, index) => {
return item.length > index;
});
//从右向左查找,返回符合条件的第一个索引
console.log(newArr);//1

//也可以用在数组对象上
const arr = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }];
const newArr = arr.findLastIndex((item, index) => {
return item.id > index;
});
//从右向左查找,返回对象元素所在位置的索引
console.log(newArr);//4

2.17 at 寻找元素

传入一个索引值,查出此索引值所对应的元素,传入负数的话,相当于 arr.length + index

此方法兼容性一般,暂时不推荐使用,node版本需要16.6.0以上 at接收一个number的参数,可以为负数,正数时获取到索引为的值,当参数为负数时,从右向左查找对应的值

1
2
3
4
5
6
7
8
const arr = ["March", "Jan", 6, 2, "A", "a"];
//正数与直接索引取值无异
const newArr = arr.at(2);
console.log(newArr);//6
//从右向左找 可以简化代码量,有些情况下效果很明显
const newArr = arr.at(-2);
//等价于 const newArr = arr.at(arr.length - 2);
console.log(newArr);//A

2.18 of 生成数组

你可以理解为他可以用来生成一个数组吧,平时很少用

1
2
3
4
5
6
7
8
9
const newArr = Array.of("March", "Jan", 6, 2, "A", "a");
console.log(newArr);//[ 'March', 'Jan', 6, 2, 'A', 'a' ]

//使用of创建数组和直接使用Array实例创建数组有所不同
const newArr = Array.of(6);
const arr = Array(6);
//传入6 of则创建一个只包含6得数组,Array传入6则创建有六个空位置得数组
console.log(newArr, arr);
//[ 6 ] [ <6 empty items> ]

2.19 ⭐toString 转字符串

它等同于 arr.join(‘,’),将数组用逗号分隔,转成一个字符串

toString是几乎所有数据类型都有的一个方法,就是单纯的转换成字符串,数组中转换成字符串默认以‘,’号隔开,有一个小技巧,如果多维数组的类型都是值类型的,可以使用toString进行扁平化

1
2
3
4
5
6
7
8
9
10
//简单的数组转字符串
const arr = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr.toString();
console.log(newArr);//March,Jan,6,2,A,a

//不论是几维数组,在toString的时候都会转化成字符串,在使用字符串方法转成数据就可以了
//弊端是因为转的时候是toString转换成了字符串,任意值类型到最后都是字符串形式,undefined和null则会转换成空字符串
const arr = [[["March"]], [[[["Jan"]]]], [[[6]]], [[2]], [[["A"]]], [[["a"]]]];
const newArr = arr.toString().split(",");
console.log(newArr);//[ 'March', 'Jan', '6', '2', 'A', 'a' ]

2.20 toLocaleString 转字符串

toLocaleString() 方法返回一个字符串,表示数组中的所有元素。每个元素通过调用它们自己的 toLocaleString 方法转换为字符串,并且使用特定于语言环境的字符串(例如逗号“,”)分隔开

此方法用于格式转换,最后返回字符串代表数组中所有的元素,接收两个参数第一个带有 BCP 47 语言标签的字符串,或者此类字符串的数组。对于 locales 参数的一般形式和说明,可以参见 Intl 主页面的参数说明。第二个,一个具有配置属性的对象。对于数字,请参见 Number.prototype.toLocaleString();对于日期,请参见 Date.prototype.toLocaleString()

此方法的使用方法记得东西比较多,详细使用方法可以点击上面的链接查看

1
2
3
4
5
6
7
8
9
10
11
12
13
const arr = ["¥7", 500, 8123, 12];
const newArr = arr.toLocaleString("ja-JP", { style: "currency", currency: "JPY" });
console.log(newArr);//¥7,¥500,¥8,123,¥12
//如果不传参数,则效果于toString一样
const newArr = arr.toLocaleString();
console.log(newArr);//¥7,500,8,123,12


const array1 = [1,'a',new Date('21 Dec 1997 14:12:00 UTC')];
const localeString = array1.toLocaleString('en',{timeZone:'UTC'})
console.log(localestring);
//Expected output:"1,a,12/21/1997,2:12:00PM",
//This assumes "en"locale and UTC timezone your results may vary

2.21 ⭐keys 返回索引集合可迭代对象

获取数组的所有索引,并返回成一个可迭代对象

返回一个只包含键的迭代对象,使用方法与entries一致

1
2
3
4
5
6
7
8
9
10
11
12
13
const arr = ["March", "Jan", 6, 2, "A", "a"];
//返回只包含键的可迭代对象,数组中的键也就是索引
const newArr = arr.keys();
//使用for...of..遍历打印
for (const iterator of newArr) {
console.log(iterator);
}
//0
//1
//2
//3
//4
//5

2.22 ⭐values 返回元素集合可迭代对象

获取数组的所有元素,并返回一个可迭代对象

返回一个只包含值得可迭代对象,使用方法与entries一致

1
2
3
4
5
6
7
8
9
10
11
12
13
const arr = ["March", "Jan", 6, 2, "A", "a"];
//返回只包含键的可迭代对象,数组中的键也就是索引
const newArr = arr.values();
//使用for...of..遍历打印
for (const iterator of newArr) {
console.log(iterator);
}
//March
//Jan
//6
//2
//A
//a

2.23 ⭐entries 返回键值对集合可迭代对象

获取的数组的所有索引和元素,组成一个一个的键值对数组,并返回一个可迭代对象

返回一个数组迭代器对象,数组迭代器( array[Symbol.iterator]),

如果不太清楚的可以看一下Symbol篇章,或者点击数组迭代器查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const arr = ["March", "Jan", 6, 2, "A", "a"];
//返回迭代器对象,有一个next方法,使用next方法会返回一个对象,里面value值就是我们想要的值
const newArr = arr.entries();
//查看的时候需要使用next,value为我们想要的值,done是否结束
console.log(newArr.next());//{ value: [ 0, 'March' ], done: false }
console.log(newArr.next());//{ value: [ 1, 'Jan' ], done: false }
console.log(newArr.next());//{ value: [ 2, 6 ], done: false }
console.log(newArr.next());//{ value: [ 3, 2 ], done: false }
console.log(newArr.next());//{ value: [ 4, 'A' ], done: false }
console.log(newArr.next());//{ value: [ 5, 'a' ], done: false }
//已经没有值了,并且done变成了true
console.log(newArr.next());//{ value: undefined, done: true }

//entries返回一个迭代器对象,所以可以被for...of..遍历
for (const iterator of newArr) {
console.log(iterator);
}
//[ 0, 'March' ]
//[ 1, 'Jan' ]
//[ 2, 6 ]
//[ 3, 2 ]
//[ 4, 'A' ]
//[ 5, 'a' ]

2.24 Array 生成数组

1
2
console.log(Array(8))
//<8 empty items>

2.25 Array.form & 拓展运算符 转化

  • Array.from:把一个类数组转成真正的数组
  • 拓展运算符:把一个类数组转成真正的数组,也可以用于剩余参数,数组解构

此方法可以将一些可迭代的以及为数组的数据转换成真正的数组,并返回一个那个新数组,比如字符串,dom伪数组等,

接收两个参数:

第一个为要转化的参数,

第二个是一个回调函数(可选)

回调函数有两个参数当前遍历的对象和索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const newArr = Array.from("March");
console.log( newArr);//[ 'M', 'a', 'r', 'c', 'h' ]

(function () {
//arguments为一个伪数组,转化成真正的数组,并经过第二个回调函数进行处理返回
const arr = Array.from(arguments, (item, index) => item + index);
console.log(arr,Array.isArray(arr));//[ 1, 4, 6, 8 ] true
})(1, 3, 4, 5);


function fn (name,age){
console.log(arguments)
//[Arguments]{'0':'sunshine lin','1':20}
console.log(Array.from(arguments))
//['sunshine lin',20]
console.log([...arguments])
//['sunshine_lin',20]
}
fn('sunshine lin',20)
//[Arguments]{'0':'sunshine_lin','1':20}

2.26 Array.formAsync

Array.fromAsync() 静态方法可以由一个异步可迭代对象、可迭代对象或类数组对象创建一个新的、浅拷贝的 Array 实例。

我理解它是 Array.from 的异步版本

Array.fromAsync() 迭代异步可迭代对象的方式与 for await...of 很相似。Array.fromAsync() 在行为上与 Array.from() 几乎等价

  • Array.fromAsync() 可以处理异步可迭代对象。
  • Array.fromAsync() 返回一个会兑现为数组实例的 Promise
  • 如果使用非异步可迭代对象调用 Array.fromAsync(),则要添加到数组中的每个元素(无论是否为 Promise)都会先等待其兑现
  • 如果提供了 mapFn,则其输入和输出会在内部等待兑现。

Array.fromAsync()Promise.all() 都可以将一个 promise 可迭代对象转换为一个数组的 promise。然而,它们有两个关键区别:

  • Array.fromAsync() 会依次等待对象中产生的每个值兑现。Promise.all() 会并行等待所有值兑现。
  • Array.fromAsync() 惰性迭代可迭代对象,并且不会获取下一个值,直到当前值被兑现。Promise.all() 预先获取所有值并等待它们全部兑现。
1
2
3
4
5
6
7
8
9
10
//我也没用过,凑合看吧  手动滑稽(≧∇≦)ノ
const asyncIterable = (async function* () {
for (let i = 0; i < 5; i++) {
await new Promise((resolve) => setTimeout(resolve, 10 * i));
yield i;
}
})();

Array.fromAsync(asyncIterable).then((array) => console.log(array));
// [0, 1, 2, 3, 4]

2.27 ⭐Array.isArray 判断类型

用来判断一个数据的类型是否为数组

也可用instanceof,参考检测数组

在类型判断的时候,我们通常使用typeof ,但是使用typeof的时候数组判断出来的就是Object类型,可以说数组是特殊的对象,使用typeof判断不出数组,就可以使用Array.isArray方法

1
2
3
4
5
6
7
8
(function () {
//在这可以看出arguments并不是一个数组
console.log(Array.isArray(arguments));//false
})(1, 3, 4, 5);

const arr = ["March", "Jan", 6, 2, "A", "a"];
//看的出是可以识别出来的 但typeof却识别不出来
console.log(typeof arr, Array.isArray(arr));//object true

3. 兼容性不好的数组方法(4个)

接下来讲一些比较新的方法,它们得要有高版本的浏览器或者nodejs版本才支持,否则不支持

3.1 toReversed 反转

用法和 reverse 大致一样,唯一不同的就是 reverse 会改变原数组,但是 toReversed 是返回一个全新的反转后的数组,

并不会修改原数组

此方法兼容性不好,暂时不推荐使用,node版本需要20.0.0以上,浏览器就不用说了

使用reverse可以反转数组,但是会改变原数组,如果不想让原数组改变的并反转数组的话就可以使用它的复制版本toReveresed

1
2
3
4
const arr1 = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr1.toReversed();

console.log(newArr);//[ 'a', 'A', 2, 6, 'Jan', 'March' ]

3.2 toSorted 排序

用法和 sort 大致一样,唯一不同的就是 sort 会改变原数组,但是 toSorted 是返回一个全新的排序后的数组,

并不会修改原数组

此方法兼容性不好,暂时不推荐使用,node版本需要20.0.0以上,浏览器就不用说了

使用sort可以反转数组,但是会改变原数组,一样的可以使用toSorted,不会改变原数组,会返回一个排好序的数组,接受的参数和sort一致,参考sort

1
2
3
const arr1 = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr1.toSorted();
console.log(newArr);//[ 2, 6, 'A', 'Jan', 'March', 'a' ]

3.3 toSpliced 截取

用法和 splice 大致一样,唯一不同的就是 splice 会改变原数组,但是 toSpliced 并不会修改原数组

此方法兼容性不好,暂时不推荐使用,node版本需要20.0.0以上,浏览器就不用说了

使用splice可以对数组进行截取和指定位置新增数据,但是会改变原数组,可以使用toSpliced,不会改变原数组,会返回一个新的数组,接受的参数使用方法和splice一致,参考splice

1
2
3
const arr1 = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr1.toSpliced(0, 1, 4);
console.log(newArr);//[ 4, 'Jan', 6, 2, 'A', 'a' ]

3.4 with 修改

以前想修改数组的某个元素,需要通过索引去修改,但是这样会修改到原数组,而使用 with 去修改的话,不会影响原数组

此方法兼容性不好,暂时不推荐使用,node版本需要20.0.0以上,浏览器就不用说了

我们都知道,我们再修改数组中得某一个值得时候可以使用arr[index]=xxx 来进行修改,但是这样是改变了原数组,当我们既想使用索引值来改变某一个值,还不想改变原数组得时候就可以使用with方法,它接收两个参数:

第一个为索引值,

第二个是要修改成为数据

1
2
3
4
const arr = ["March", "Jan", 6, 2, "A", "a"];
const newArr = arr.with(3, "Tom");

console.log(newArr);//[ 'March', 'Jan', 6, 'Tom', 'A', 'a' ]

4. ⭐巧用数组作判断

项目中的一个小需求点,点击按钮,验证几十个条件框,判断所有条件框是否填写(选择)过数据(至少有一个条件判断为真)再执行对应操作

判断的条件框包含 Radio 单选框,Checkbox 多选框,Input 输入框,InputNumber 计数器, Select 选择器, Switch 开关等

项目使用的 Element 组件库 V2.15.6

4.1 不同条件对应的数据类型以及默认值

  • Radio 单选框 string ''
  • Checkbox 多选框 array []
  • Input 输入框 string ''
  • InputNumber 计数器 number 0
  • Select 选择器
    • 单选 string ''
    • 多选 array []
  • Switch 开关 boolean false

4.2 代码实现

思路一

直接用 if 判断开干,然后大概代码如下(变量为模拟变量)

1
2
3
4
5
6
7
8
9
10
11
12
// 多条件判断开始,如下

if (obj.radio1 || obj.checkbox1.length > 0 || obj.input1 || obj.inputNumber1 > 0 || obj.select1 || obj.select2.length > 0 || obj.switch1 || obj.radio2 || obj.checkbox2.length > 0 || obj.input2 || obj.inputNumber2 > 0 || obj.select3 || obj.select4.length > 0 || obj.switch2 ...) {
// do something
} else {
// 条件不符,提示
this.$message({
message: '请选择条件后重试',
type: 'warning'
})
return false
}

实际项目场景中的变量名因为语义化字符很多, if 判断没写几个就写了很长一串, 然后写了几个就写不动了(感觉在写一坨 shi )

能不能用更优雅的方式实现呢?

思路二

把这些需要判断的变量放到一个数组里,用 map 处理,使用 includes 判断数组中是否包含指定的 Boolean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 多条件判断开始,如下

const arr = [
obj.radio1,
obj.checkbox1.length,
obj.input1,
obj.inputNumber1,
obj.select1,
obj.select2.length,
obj.switch1,
obj.radio2,
obj.checkbox2.length,
obj.input2,
obj.inputNumber2,
obj.select3,
obj.select4.length,
obj.switch2
...
]

const arr1 = arr.map(item => Boolean(item))
if (arr1.includes(true)) {
// do something
} else {
// 条件不符,提示
this.$message({
message: '请选择条件后重试',
type: 'warning'
})
return false
}

思路三

把这些需要判断的变量放到一个数组里,用 some处理成 Boolean 类型,会自动返回Boolean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const arr = [
obj.radio1,
obj.checkbox1.length,
obj.input1,
obj.inputNumber1,
obj.select1,
obj.select2.length,
obj.switch1,
obj.radio2,
obj.checkbox2.length,
obj.input2,
obj.inputNumber2,
obj.select3,
obj.select4.length,
obj.switch2
...
]

const res = arr.some(item => Boolean(item))
if (res) {
// do something
} else {
// 条件不符,提示
this.$message({
message: '请选择条件后重试',
type: 'warning'
})
return false
}

//最直白的some解析判断
const boolean = ['', [].length, false, 0]
const res=boolean.some((item) => Boolean(item))
console.log(res)//false
//只有当 String!=='' || [].length!==0 || Boolean=!false || number!==0 时才会返回真值true

//可以考虑使用every方法,全为真才通过
const boolean1 = ['', [].length, false, 0]
const res1=boolean.every((item) => Boolean(item))

5. 参考

2023年了,数组居然都有43个方法了!带你们盘点一下?

不数不知道,JS数组已经有42个方法了

让 js 中的 if 判断如丝般顺滑