前言
最近感觉自己对数组遍历的方法有点混乱,for循环、forEach( )、map( )等方法混合使用,没有一个统一的规范,所以就打算总结一下。
ES5中的数组遍历方法
ES5为数组定义了5个迭代方法。每个方法都接受两个参数:要在每一项上运行的函数和(可选的)运行该函数的作用域对象——影响
this
的值。
而传入的函数又可以接受三个参数:当前遍历的数组项的值,该项在数组中的位置和数组对象本身。
every( )
对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则every( )返回true。例如:
let numbers = [1, 2, 3, 4];
let everyResult = numbers.every((item, index, array)=>{
return item > 1;
})
console.log(everyResult); // 输出 false
filter( )
即对数组中的每一项运行给定函数,然后返回该函数会返回true的项。从名字就看得出来,这个方法是用来过滤数组项的,例如:
let numbers = [1, 2, 3, 4];
let filterResult = numbers.filter((item, index, array)=>{
return item > 1;
})
console.log(filterResult); // 输出 [2, 3, 4]
forEach( )
对数组的每一项运行给定函数。forEach方法是唯一一个没有返回值的,纯粹用来遍历数组。
let numbers = [1, 2, 3, 4];
numbers.forEach((item, index, array)=>{
// 执行某些操作
})
map( )
对数组的每一项运行给定函数,返回每次函数调用的返回值组成的数组。map方法就是有返回值的forEach方法,例如:
let numbers = [1, 2, 3, 4];
let mapResult = numbers.map((item, index, array)=>{
return item * 2;
})
console.log(mapResult); // 输出 [2, 4, 6, 8]
some( )
对数组的每一项运行给定函数,如果该函数对任一项返回true,则some( )就返回true。some和every就像 ||
和 &&
,some是只要有一项满足,就返回true。
let numbers = [1, 2, 3, 4];
let someResult = numbers.some((item, index, array)=>{
return item > 3;
})
console.log(someResult); // 输出 true
ES5的这几个迭代方法,如果是只对item
(当前遍历的数组项)进行操作,是不会改变原数组的,但是也可以通过给定函数中接收的index
参数来改变原数组
除了ES5这几个方法,还有常见的简单for循环和ES6的for...of。
for...of
ES6借鉴了Java、Python等语言,引入了for...of
循环。for...of
主要用来统一ES6多种数据结构的遍历方法,不仅可以遍历数组,还可以遍历Map
、Set
这两种ES6新推出的数据结构。只要具有iterator
接口的数据结构,就可以用for...of循环来遍历。还可以遍历某些类似数组的对象,比如arguments对象、DOM NodeList 对象。
let numbers = [1, 2, 3, 4];
for(let item of numbers){
console.log(item);
}
//输出
// 1
// 2
// 3
// 4
有关ES6新特性的内容,可以参考阮一峰老师的ES6入门教程
不推荐使用for...in
来遍历数组,只用来遍历对象的属性。
性能分析
这里主要测试一下for循环
、forEach
、for...of
、map
、for...in
这几个方法遍历一个长度为100000的数组所耗费的时间。
//测试数据: arr = [1,2,3,4,...,99999,100000];
//普通for循环
console.time('普通for循环');
for(let i=0; i<arr.length; i++){
}
console.timeEnd('普通for循环')
//控制台输出 => 普通for循环: 0.923095703125ms
//forEach循环
console.time('forEach循环');
arr.forEach((item)=>{
})
console.timeEnd('forEach循环')
//控制台输出 => forEach循环: 1.973876953125ms
console.time('for...of循环');
for(let item of arr){
}
console.timeEnd('for...of循环')
//控制台输出 => for...of循环: 3.5810546875ms
//for...in循环
console.time('for...in循环');
for(let item in arr){
}
console.timeEnd('for...in循环')
//控制台输出 => for...in循环: 15.35693359375ms
//map循环循环
console.time('map循环');
arr.map((item) => {
})
console.timeEnd('map循环')
//控制台输出 => map循环: 19.4990234375ms
可能由于电脑配置等问题,这里你的控制台输出可能会不一样,甚至你刷新一下浏览器,两次的输出也会不一致。这里map( )
居然比for...in
的性能还低,印象中是for...in
最低的,可能是因为测试的次数太少,有待研究。
总结
从性能上来说,for循环
> forEach
> for...of
> for...in
> map
,所以一般来说使用for循环
是性能最高的,但是写法稍微复杂了点。但是性能好和要使用哪种遍历方法并没有太大关系,以现在的硬件水平来说,这里的性能差异完全可以忽略。所以一般来说,还需要考虑语义和功能需求。
如果你需要将数组按照给定规则转换并返回该结果数组,就使用map
。
如果你需要进行简单的遍历,用 forEach
或者 for of
,但是 forEach
不能通过return和break语句来终止循环,所以如果需要中途终止循环,就使用 for...of
或者 for循环
。
如果是在遍历数组的同时,需要改变原数组中的对应项,就用for循环
。
for...in
会把数组所拥有可枚举的属性都遍历一次,所以可能会有意想不到的结果,不推荐用来遍历数组。
另外的三个,every( )
、filter( )
、some( )
按功能需要来使用即可。