简述forEach、map、filter、every、some、find、findIndex
forEach()
用于遍历数组,无返回值
1.基础点
forEach的使用频率很高,多用于对数组自身的改变和各元素相关统计性的计算,重要特性如下:
- 可以
改变数组自身
,没有返回值
; - 中途不能用常规操作跳出循环,可以用抛出异常(try/catch)的方式,但不推荐这样做;
2.易错点
- forEach()数组中的元素是
值类型
场景下
forEach()不一定改变自身数组。
示例一
var arr=[1,2,5,7,3];
arr.forEach(item=>item*2);
console.log(arr); //[1,2,5,7,3]
可以看到并没有改变数组的元素值,那么我们来看下面的
示例二
var arr=[1,2,5,7,3];
arr.forEach((item,index,arr)=>arr[index]=item*2);
console.log(arr); // [2, 4, 10, 14, 6]
可以看到,forEach()可以传入一个匿名函数作为参数,而该匿名函数又含有三个参数,其依次代表
数组遍历时的当前元素item
数组遍历时的当前元素的索引index
正在遍历的数组array
有了这三个参数,可以方便我们做很多事情,比如说示例当中将每一项数组元素翻倍,这时需要用到第一个参数item。
但是,仅仅只是将item乘以2可不行,我们还得将其赋值给原来的数组,这时我们就得用到后面两个参数index和array。
- forEach()数组中的元素是
引用类型
场景下
示例
var arr=[
{name:'tom',age:16},
{name:'lily',age:17}
];
arr.forEach(item => {
item.age = item.age + 1}
);
//arr => [{name:'tom',age:17},{name:'lily',age:18}]
arr中发生了改变,tom、lily都长了一岁。
- 不支持链式操作
以下代码是错误的:
[1,2,3,4,5].forEach(
item => console.log(item))
.filter(item => {
return item > 2
})
// Uncaught TypeError: Cannot read property 'filter' of undefined
注意:这里我们说仅仅是forEach()这个方法不支持链式调用,在调用forEach之前,前面的数组你怎么玩链式都没问题,最后返回一个正常数组即可:
// 这个没问题
[1,2,3,4,5].filter(item => {
return item > 2})
.forEach(item => {
console.log(item)
})
3.总结
- 当数组中元素是
值类型
,forEach绝对不会改变数组,但可以采用把改变后的值item*2
赋值给原来的位置,即arr[index]
- 当数组中元素是
引用类型
,则可以改变数组
(因为引用的是同一个地址,其实修改的是引用对象内的元素) - forEach没有返回值(即便你给forEach加上return也没用),这也间接说明forEach不支持链式调用
map()
用于遍历数组,返回处理之后的新数组
1.基础点
- 与forEach()的功能类似,但forEach()的一些局限性它很多都能解决。
- "map"即"映射",也就是原数组被"映射"成对应新数组,
需要有承载对象
,这样处理数组后也不会影响到原有数组
。 - map()中每个元素都要执行相应的回调函数,然后返回结果,所以必须要有return。
2.易错点
创建新数组不代表不能用它改变原有数组,你用原有数组去承载就可以:
let arr = [1,2,3];
arr = arr.map(item => { return item * 2 })
console.log(arr); //[2,4,6]
原数组也可以被改变,多用于直接修改原数组的情况,用起来很简单。
数组中的元素是引用类型时,map会将改变的值复制一份出来:
var potatos = [
{ id: '1001', weight: 50 },
{ id: '1002', weight: 80 },
{ id: '1006', weight: 60 }];
//potatos.forEach(item=>item.weight+=10);
potatos=potatos.map(item=>item.weight+=10);
console.log(potatos); //[60,90,70]
可以看到有时候并不是我们想要的结果。
用forEach就不会有这个顾虑,//potatos = [{ id: '1001', weight: 60 },{ id: '1002', weight: 90 },{ id: '1006', weight: 70 }],但是forEach是在原数组上做的修改。
可以根据自己的需求来选择使用哪个。
filter()
用于筛选数组中满足条件的元素,返回一个筛选后的新数组
1.基础点
map()没法做到的过滤,就交给filter()去完成
let newArr = [1,2,3,4,5].filter(item =>{
return item > 3
})
// => [4,5]
2.这个也没什么易错点
every()
用于判断数组中的每一项元素是否都满足条件,返回一个布尔值
1.基础点
它用于检测数组中的每一项是否都满足条件,只有都满足了才会返回true。
var arr=[2,5,-3,-1,4];
//判断arr中是不是每一项都大于0
var isEvery = arr.every(function(item,index,array){
return item > 0;
});
console.log(isEvery); // false
2.总结
- every返回值是布尔类型
- every对每一个元素执行一个callback,直到它找到一个使 callback 返回 false的元素,就返回false,之后的不再执行;
- 直到遍历完成也没有返回false的话,就返回true。
some()
用于判断数组中的是否存在满足条件的元素,返回一个布尔值。
1.基础点
用于检测数组中是否有符合条件的元素,只要有一个满足即返回true,之后的不再执行(所以说对性能很友好!)。
var arr=[2,5,-3,-1,4];
var isSome = arr.some(function(item,index,array){
return item < 0;
});
console.log(isSome); // true
判断arr中有没有小于0的元素,很显然有小于0的元素,所以返回true。
2.总结
- some返回值是布尔类型
- some对每一个元素执行一个callback,直到它找到一个使 callback 返回 true的元素,就返回true,之后的不再执行;
- 直到遍历完成也没有返回true的话,就返回false。
- 如果说some()是"||"判断,那every()就是"&&"判断
获取数组中的指定元素
在工作中我们还有一个比较常见的场景,就是在数组中找到我想要的那一个,并且返回给我。
some()已经办不到了,它只会告诉我是否存在,filter()确实可以做到,但是如果我本身就知道这个数组里即使有我想的那个,也肯定只有一个,不可能出现多个,所以,出于性能的考虑,我不想用filter()给我从头遍历到尾,这样怎么办?
1.find()
find()用于查找数组中第一个满足条件的元素,返回找到的第一个符合条件的值。
- 就是用来在数组中找到我们所需要的元素,并且和some()一样,只要有一个满足即返回该元素,不会多余遍历,对性能很友善。
- 如果没有找到,返回undefined
var arr=[1,4,2,6,3,7];
var big=arr.find(item=>item>5);
console.log(big); //6
找到第一个符合条件的元素,就不再往后找。
2.findIndex()
也是查找数组中目标元素,找到就返回元素的位置,找不到就返回-1。
- 也是只要有一个满足即返回该元素,后边的不再查找。
var arr=[1,4,2,6,3,7];
var bigIndex=arr.findIndex(item=>item>5);
console.log(bigIndex); //3