JS数组遍历方式与性能深度解析

作者:缓存笔记时间:2026-10-24 19:38:01浏览:244

本文深入对比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来遍历数组。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章