JS数组遍历方式与性能深度解析
本文深入对比JavaScript中数组遍历的多种方法,包括for、forEach、map、filter及ES6的for...in和for...of。通过基准测试发现,缓存长度的传统for循环性能最佳,而for...in因遍历原型链属性导致效率最低。文章提供了各方法的适用场景建议,帮助开发者在开发中根据需求选择最高效的遍历方式。
数组的方法
随着JavaScript技术的演进,目前提供了丰富的数组操作API。下文图表展示了大部分数组方法,本文重点聚焦于数组遍历机制及其性能差异。面对众多方法,掌握如何选择性能最优的方案,对提升开发效率至关重要。

数组遍历的方法
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])
}
通过引入临时变量缓存数组长度,避免在每次循环中重复获取length属性。当数组规模较大时,这种优化带来的性能提升尤为显著。
在各类循环遍历方法中,此方式通常拥有最高的执行效率。
forEach
- 普通forEach
该方法对数组中的每个元素执行提供的回调函数,不返回任何值,常用于单纯的元素遍历操作。
var arr5 = [10,20,30]
var result5 = arr5.forEach((item,index,arr)=>{
console.log(item)
})
console.log(result5)
/*
10
20
30
undefined 该方法没有返回值
*/
作为Array内置方法,forEach使用频率较高,但其实际运行性能通常弱于普通的for循环。
- 原型forEach
鉴于forEach是Array类型的专属方法,NodeList等非数组类型无法直接调用。此变体通过调用Array.prototype.forEach.call(),使类似数组的对象也能具备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=["前端","南玖","ssss"];
for (let item of arr){
console.log(item)
}
//前端 南玖 ssss
//遍历对象
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引入的特性,其性能优于for...in,但仍不及普通的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。
- 遍历类数组对象(ES6)推荐使用for...of。
- 获取对象属性名集合推荐使用Object.keys()。
为何for… in会慢?
因为for...in语法是首个用于迭代对象键的JavaScript语句。遍历对象键({})与在数组([])上循环不同,引擎需执行额外工作来追踪已迭代的属性。因此,不建议使用for...in来遍历数组。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
为什么JS调用reload后页面没有立即更新
2026-11-05 13:38:29
crypto-js 加密结果与 Java/Python 后端不一致怎么解决
2026-11-05 12:09:48
js文件缓存导致代码不更新怎么强制刷新
2026-11-04 22:30:24
JS逆向调试技巧:编写Hook脚本监控加密函数输入输出
2026-11-04 10:42:46
Babylon.js 性能优化技巧:实例化网格与遮挡剔除
2026-11-03 23:43:22
