数组遍历的方法
for
标准的for循环语句,也是最传统的循环语句
var arr = [1, 2, 3, 4, 5];
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
最简单的一种遍历方式,也是使用频率最高的,性能较好,但还能优化
优化版for循环语句
var arr = [1, 2, 3, 4, 5];
for (var i = 0, len = arr.length; i < len; i++) {
console.log(arr[i]);
}
使用临时变量,将长度缓存起来,避免重复获取数组长度,尤其是当数组长度较大时优化效果才会更加明显。
这种方法基本上是所有循环遍历方法中性能最高的一种
forEach
普通forEach
对数组中的每一元素运行给定的函数,没有返回值,常用来遍历元素
var arr5 = [10, 20, 30];
var result5 = arr5.forEach((item, index, arr) => {
console.log(item);
});
console.log(result5);
/*
10
20
30
undefined 该方法没有返回值
*/
数组自带的foreach循环,使用频率较高,实际上性能比普通for循环弱
原型forEach
由于foreach是Array型自带的,对于一些非这种类型的,无法直接使用(如NodeList),所以才有了这个变种,使用这个变种可以让类似的数组拥有foreach功能。
const nodes = document.querySelectorAll("div");
Array.prototype.forEach.call(nodes, (item, index, arr) => {
console.log(item);
});
实际性能要比普通foreach弱
for…in
任意顺序遍历一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。
一般常用来遍历对象,包括非整数类型的名称和继承的那些原型链上面的属性也能被遍历。像 Array和 Object使用内置构造函数所创建的对象都会继承自Object.prototype和String.prototype的不可枚举属性就不能遍历了.
var arr = [1, 2, 3, 4, 5];
for (var i in arr) {
console.log(i, arr[i]);
} //这里的i是对象属性,也就是数组的下标
/**
0 1
1 2
2 3
3 4
4 5 **/
大部分人都喜欢用这个方法,但它的性能却不怎么好
for…of(不能遍历对象)
在可迭代对象(具有 iterator 接口)(Array,Map,Set,String,arguments)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句,不能遍历对象
let arr = ["前端", "面试题宝典", "真好用"];
for (let item of arr) {
console.log(item);
}
//遍历对象
let person = { name: "前端面试题宝典", age: 18, city: "上海" };
for (let item of person) {
console.log(item);
}
// 我们发现它是不可以的 我们可以搭配Object.keys使用
for (let item of Object.keys(person)) {
console.log(person[item]);
}
// 南玖 18 上海
这种方式是es6里面用到的,性能要好于forin,但仍然比不上普通for循环
map
map: 只能遍历数组,不能中断,返回值是修改后的数组。
let arr = [1, 2, 3];
const res = arr.map((item) => {
return item + 1;
});
console.log(res); //[2,3,4]
console.log(arr); // [1,2,3]
every
对数组中的每一运行给定的函数,如果该函数对每一项都返回true,则该函数返回true
var arr = [10, 30, 25, 64, 18, 3, 9];
var result = arr.every((item, index, arr) => {
return item > 3;
});
console.log(result); //false
some
对数组中的每一运行给定的函数,如果该函数有一项返回true,就返回true,所有项返回false才返回false
var arr2 = [10, 20, 32, 45, 36, 94, 75];
var result2 = arr2.some((item, index, arr) => {
return item < 10;
});
console.log(result2); //false
reduce
reduce()
方法对数组中的每个元素执行一个由你提供的reducer函数(升序执行),将其结果汇总为单个返回值
const array = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
filter
对数组中的每一运行给定的函数,会返回满足该函数的项组成的数组
// filter 返回满足要求的数组项组成的新数组
var arr3 = [3, 6, 7, 12, 20, 64, 35];
var result3 = arr3.filter((item, index, arr) => {
return item > 3;
});
console.log(result3); //[6,7,12,20,64,35]
性能测试
工具测试
使用工具测试性能分析结果如下图所示
手动测试
我们也可以自己用代码测试:
//测试函数
function clecTime(fn, fnName) {
const start = new Date().getTime();
if (fn) fn();
const end = new Date().getTime();
console.log(`${fnName}执行耗时:${end - start}ms`);
}
function forfn() {
let a = [];
for (var i = 0; i < arr.length; i++) {
// console.log(i)
a.push(arr[i]);
}
}
clecTime(forfn, "for"); //for执行耗时:106ms
function forlenfn() {
let a = [];
for (var i = 0, len = arr.length; i < len; i++) {
a.push(arr[i]);
}
}
clecTime(forlenfn, "for len"); //for len执行耗时:95ms
function forEachfn() {
let a = [];
arr.forEach((item) => {
a.push[item];
});
}
clecTime(forEachfn, "forEach"); //forEach执行耗时:201ms
function forinfn() {
let a = [];
for (var i in arr) {
a.push(arr[i]);
}
}
clecTime(forinfn, "forin"); //forin执行耗时:2584ms (离谱)
function foroffn() {
let a = [];
for (var i of arr) {
a.push(i);
}
}
clecTime(foroffn, "forof"); //forof执行耗时:221ms
// ...其余可自行测试
结果分析
经过工具与手动测试发现,结果基本一致,数组遍历各个方法的速度:传统的for循环最快,for-in最慢
for-len
>
for>
for-of>
forEach>
map>
for-in
javascript原生遍历方法的建议用法:
- 用
for
循环遍历数组 - 用
for...in
遍历对象 - 用
for...of
遍历类数组对象(ES6) - 用
Object.keys()
获取对象属性名的集合
为何for… in会慢?
因为for … in
语法是第一个能够迭代对象键的JavaScript语句,循环对象键({})与在数组([])上进行循环不同,引擎会执行一些额外的工作来跟踪已经迭代的属性。因此不建议使用for...in
来遍历数组