ES5常用遍历数组方法
forEach
最基础的遍历方法,循环数组每一项,参数(指function的参数)包含每一项,每一项索引,数组本身.
let arr = [1, 3, 5, 7, 9]
arr.forEach((item, index, array) => {
console.log(item, index, array);
})
//输出结果
//1 0 [1, 3, 5, 7, 9]
//3 1 [1, 3, 5, 7, 9]
//5 2 [1, 3, 5, 7, 9]
//7 3 [1, 3, 5, 7, 9]
//9 4 [1, 3, 5, 7, 9]
forEach没有返回值,并且不能改变数组本身
let arr = [1, 3, 5, 7]
arr.forEach((item, index, array) => {
item = item * 2
})
console.log(arr)
//输出 [1, 3, 5, 7] 并没有改变数组本身
let newArr = arr.forEach((item, index, array) => { })
console.log(newArr);
//输出 undefined foreach没有返回值
有人一定有疑惑,平时工作都是直接使用forEach来改变原数组内容的,例如后端返回一个数组,要根据数组的value来决定是true/fasle
arr = [
{ id: 1, name: 'a', value: 0 },
{ id: 2, name: 'b', value: 0 },
{ id: 3, name: 'c', value: 1 }
]
//处理数组 value 1处理为true 0处理为false
arr.forEach(item => {
item.value = item.value == 1 ? true : false
})
console.log(arr);
//输出结果
// [
// { id: 1, name: 'a', value: false },
// { id: 2, name: 'b', value: false },
// { id: 3, name: 'c', value: true }
// ]
arr确实被成功修改了,每一项的value被替换成了布尔值,那forEach不能修改数组本身是不是错的呢? 并不是,在看下面例子
arr = [
{ id: 1, name: 'a', value: 0 },
{ id: 2, name: 'b', value: 0 },
{ id: 3, name: 'c', value: 1 }
]
arr.forEach(item => {
item = item.value == 1 ? true : false
})
console.log(arr);
//输出结果
// [
// { id: 1, name: 'a', value: 0 },
// { id: 2, name: 'b', value: 0 },
// { id: 3, name: 'c', value: 1 }
// ]
同样的操作,这次数组并没有发生变化,两次的区别是什么?第一次我们修改的是数组每项对象的一个值,而第二次修改的是每项对象的整体.我们知道对象属于是引用数据类型
,可以理解为一个指针,它指向一个地址,而我们修改它内部的值等同于修改它指向地址里的内容.不算修改数组本身,而我们修改对象整体等于修改了数组每项指针地址,这就是等于修改数组本身,所以不会成功.
常用场景:需要对数组的每项数据进行操作
map
映射,和foreach功能基本类似,参数相同,不修改原始数组,有区别的是它有返回值
let arr = [1, 3, 5, 7]
let newArr = arr.map(item => {
return item + 1
})
console.log(newArr);
//输出结果 newArr接收到了返回值
// [2, 4, 6, 8]
注意的是,map中要使用return
,不写return 会返回undefined.
有人就不服了,我不写return也是对的,咋回事?
let arr = [1, 3, 5, 7]
let newArr = arr.map(item => item + 1)
console.log(newArr);
//输出结果
// [2, 4, 6, 8]
上面代码确实不写return,也出结果了,咋回事?
我偷偷告诉你,箭头函数中如果是很简单的代码,将代码写在一行,并且去掉花括号,等于写了return,算是语法糖吧~
()=>{
return XXXX
}
()=> XXXX
//这两种写法是一样的
讲的这么细 关注我一下不过分吧😉
常用场景:需要一个新的数组,新数组的每项都与旧数组存在一定的关系。如果你并不需要一个新数组,选择使用map是违背逻辑的。
find / findIndex
find会找到数组符合项(第一个符合项),并返回该项,参数同上.
findIndex会找到数组符合项(第一个符合项),并返回该项索引,参数同上.
let arr = [1,3,5,7]
let n = arr.find((item, index) => {
console.log('执行了');
return item > 1
})
console.log(n);
//输出结果
//执行了*2
//3
let t=arr.find((item, index) => {
return item < 1
})
console.log(t);
//输出 undefined
let a = arr.findIndex((item, index) => {
console.log('执行了');
return item > 1
})
console.log(a);
//输出结果
//执行了*2
//1
let b=arr.findIndex((item, index) => {
return item < 1
})
console.log(b);
//输出 -1
1.循环里的打印只打印了两次,说明find在找到符合条件项之后,就不在继续进行,大大减少了性能损耗.
2.find在找不到符合项的情况,会返回undefined
3.findIndex找不到符合项的情况下.会返回 -1
4.同需求下用find/findIndex比用foreach+if判断,性能会有提高
常用场景:根据后台返回数据,找到默认回显/选择项
filter
找到所有符合项,并返回一个数组,不会改变原数组,参数同上
let arr = [1,3,5,7]
let newArr = arr.filter((item, index) => {
return item > 1
})
console.log(newArr);
//输出结果 [3, 5, 7]
let newArr2=arr.filter((item, index) => {
return item < 1
})
console.log(newArr2);
//输出 []
在功能上与map些许类似,都返回一个新数组.但区别与map返回的新数组项数一定与旧数组相同,而filter返回的新数组项数不一定等于旧数组.
附一个使用filter去重案例
let arr = [1, 3, 5, 7, 7, 7, 7, 7, 7]
let newArr = arr.filter((item, index, self) => {
return self.indexOf(item) === index
})
console.log(newArr);
// [1, 3, 5, 7]
常用场景:从后端返回数据结果中筛选出符合条件项,并以数组形式展现
some / every
这一对的返回结果都是布尔值,类似与&&和||的关系
some是只要有一个满足项,就返回true而every则是所有项满足条件才会返回true
记忆方法 :some有真即为真,every一假全为假.
let arr = [
{ name: 'a', value: true },
{ name: 'b', value: false },
{ name: 'c', value: true },
]
let res = arr.some(item => item.value)
console.log(res) //输出 true
let res1 = arr.every(item => item.value)
console.log(res1) //输出 false
结合案列分析,使用some时因为原数组中两个符合条件的,所以是有真即为真,返回结果是true.使用every时,存在一个不符合的,一假全为假,返回false,全为假指的是已经有一项不满足了不用继续看了,结果肯定是假,并不是说每一项都不符合
以上所有方法在数组为空时都不会执行,都不会改变原数组,并且参数都相同
reduce
这个写电商业务的经常用,常用来写购物车累计价格.
它的参数与以上其它方法多一个,第一个参数是初始值,后三个参数同上.
let arr = [1,2,3,4]
let count = arr.reduce((pre,item,index,array)=>{
console.log(pre,item,index,array);
return pre+item
},100)
//输出结果
// 100 1 0 [1,2,3,4]
// 101 2 1 [1,2,3,4]
// 103 3 2 [1,2,3,4]
// 106 4 3 [1,2,3,4]
console.log('共计',count);
//共计 110
第一个形参是初始值,100就是我们设置的初始值.运行过程是首先先获取初始值(这里是100),然后用100累加(100是我们是设置的,所以累加从数组第一项开始)
,100+1=101,101将作为下次循环的初始值,第二次循环,初始值101(上一次运算得到的)
,累加,101+2=103,103将作为下次结果.
如果不设置初始值,将用数组第一项作为初始值.
let arr = [1,2,3,4]
let count = arr.reduce((pre,item,index,array)=>{
console.log(pre,item,index,array);
return pre+item
})
//输出结果
// 1 2 1 [1,2,3,4]
// 3 3 2 [1,2,3,4]
// 6 4 3 [1,2,3,4]
console.log('共计',count);
//共计 10
这里我们没有设置初始值,所以初始值取了第一项
,进行累加的时候也不会加第一项了,是从第二项开始,首先获取初始值(没有设置,所以用数组第一项),开始累加因为第一项当默认值了,所以从第二项开始累加
,初始值1+第二项2=3,3将作为下一次循环的初始值,到二次循环,初始值3+第三项3=6作为下次循环初始值
再演示一个实际案例,计算购物车中的物品价格
let arr = [
{ name: '苹果', price: 5, num: 2 },
{ name: '香蕉', price: 3, num: 1 },
{ name: '橘子', price: 2, num: 4 },
]
let count = arr.reduce((pre, item, index, array) => {
console.log(pre, item);
return pre + item.price*item.num
}, 0)
//输出结果
// 1 2 1 [1,2,3,4]
// 3 3 2 [1,2,3,4]
// 6 4 3 [1,2,3,4]
console.log('共计',count);
// 共计 21