JavaScript数组遍历的各种方式

简介: JavaScript数组遍历的各种方式

第一种方式(for循环)

原始的for循环,也是最常见的一种遍历方式,示例如下所示:

let my_array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
for (let i = 0; i < my_array.length; i++) {
  console.log(my_array[i]);
  // 打印
  // 10
  // 20
  // 30
  // 40
  // 50
  // 60
  // 70
  // 80
  // 90
  // 100
}

第二种方式(forEach 遍历)

可以通过数组原型上的方法(forEach)进行遍历,示例如下:

let my_array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
my_array.forEach((res, index, e)=>console.log(res, index, e))
// 打印
// 10 0 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 20 1 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 30 2 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 40 3 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 50 4 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 60 5 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 70 6 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 80 7 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 90 8 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
// 100 9 [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

语法:

forEach(callbackFn)

forEach(callbackFn, thisArg)

callbackFn

回调函数为数组中每个元素执行的函数。并会丢弃它的返回值。该函数被调用时将传入以下参数:

element

数组中正在处理的当前元素。

index

数组中正在处理的当前元素的索引。

array

调用了 forEach() 的数组本身。

thisArg 可选

执行 callbackFn 时用作 this 的值。如果是采用箭头函数的形式,此参数就显得无关紧要了。

返回值

undefined

描述:

forEach() 方法是一个迭代方法

。它按索引升序地为数组中的每个元素调用一次提供的 callbackFn 函数。与 map()

不同,forEach() 总是返回 undefined

,而且不能继续链式调用。其典型的用法是在链式调用的末尾执行某些操作。

callbackFn 仅对已赋值的数组索引调用。对于稀疏数组

中的空槽,它不会被调用。

实例如下:

let my_array = new Array(10);
my_array.forEach(res=>console.log(res + '这是测试稀疏数组'));

运行代码,发现没有也没打印。

forEach() 不会改变其调用的数组,但是,作为 callbackFn 的函数可以更改数组。请注意,在第一次调用 callbackFn 之前,数组的长度已经被保存。因此:

  • 当调用 forEach() 时,callbackFn 不会访问超出数组初始长度的任何元素。
  • 已经访问过的索引的更改不会导致 callbackFn 再次调用它们。
  • 如果 callbackFn 更改了数组中已经存在但尚未访问的元素,则传递给 callbackFn 的值将是在访问该元素时的值。已经被删除的元素不会被访问。

示例如下所示:

let my_array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
my_array.forEach((res, index, e)=>{
    if(!index){
        my_array.push(1000)
    }
    console.log(res)
})
// 打印
// 10
// 20
// 30
// 40
// 50
// 60
// 70
// 80
// 90
// 100

发现在遍历数组时,新增的数据并没有打印出来。

除非抛出异常,否则没有办法停止或中断 forEach() 循环。如果有这样的需求,则不应该使用 forEach() 方法。

可以通过像  for、for...of 和 for...in 这样的循环语句来实现提前终止。当不需要进一步迭代时,诸如

some()、find() 和 findIndex() 等数组方法也会立即停止迭代。

forEach() 返回的是一个同步函数,它不会等待 Promise 的返回。

第三种方式(for...in)

for...in 语句以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。

语法

for (variable in object)

 statement

variable

在每次迭代时,variable 会被赋值为不同的属性名。

object

非 Symbol 类型的可枚举属性被迭代的对象。

注意:for ... in是为遍历对象属性而构建的,不建议与数组一起使用。

代码示例如下所示:

let my_array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
for (let index in my_array) {
    console.log(index, my_array[index]);
}
// 打印
// 0 10
// 1 20
// 2 30
// 3 40
// 4 50
// 5 60
// 6 70
// 7 80
// 8 90
// 9 100

第四种方式(for...of)

for...of语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。

语法:

for (variable of iterable) {
    //statements
}

variable

在每次迭代中,将不同属性的值分配给变量。

iterable

被迭代枚举其属性的对象。

示例如下所示:

let my_array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
for (let v of my_array) {
    console.log(v);
}
// 打印
// 10
// 20
// 30
// 40
// 50
// 60
// 70
// 80
// 90
// 100

对于for...of的循环,可以由 break, throw 或 return 终止。在这些情况下,迭代器会进行关闭。

示例代码如下所示:

let my_array = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
for (let v of my_array) {
    if(v > 60) {
        break;
    }
    console.log(v);
}
// 打印
// 10
// 20
// 30
// 40
// 50
// 60

第五种方式(map方法遍历)

map() 方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。

语法

map(callbackFn)

map(callbackFn, thisArg)

参数

callbackFn

为数组中的每个元素执行的函数。它的返回值作为一个元素被添加为新数组中。该函数被调用时将传入以下参数:

element

数组中当前正在处理的元素。

index

正在处理的元素在数组中的索引。

array

调用了 map() 的数组本身。

thisArg (可选)

执行 callbackFn 时用作 this 的值。

map() 方法是一个迭代方法。它为数组中的每个元素调用一次提供的 callbackFn 函数,并用结果构建一个新数组。

map() 方法是一个复制方法。它不会改变 this。然而,作为 callbackFn 提供的函数可以更改数组。请注意,在第一次调用 callbackFn之前,数组的长度已经被保存。因此:

  • 当开始调用 map() 时,callbackFn 将不会访问超出数组初始长度的任何元素。
  • 对已访问索引的更改不会导致再次在这些元素上调用 callbackFn
  • 如果数组中一个现有的、尚未访问的元素被 callbackFn 更改,则它传递给 callbackFn 的值将是该元素被修改后的值。被删除的元素则不会被访问。

一般数组常用的遍历方式大概就是这5种。

六、性能对比

Benchmark.js 是 loash的作者(John-David Dalton)创建的一个用于基准测试的类库。首先我们引入Benchmark.js 进行基准测试。

Benchmark.js 如何使用可参考github地址:我们创建一个数组,包含10000个元素,然后通过上面5种方式遍历以下,对比以下性能,代码如下所示:

var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;
var array10000 = Array.from({ length: 10000 }, (o, i) => i + 1);
// 增加测试
suite.add('for#Array', function() {
  for(let i = 0; i < array10000.length; i++){
  }
})
.add('forEach#Array', function() {
    array10000.forEach(res=>{})
  })
.add('forIn#Array', function() {
    for (let i in array10000){
    }
})
.add('forOf#Array', function() {
     for (let i of array10000){
    }
  })
.add('map#Array', function() {
    array10000.map(res=>{})
})
// 增加监听
.on('cycle', function(event) {
  console.log(String(event.target));
})
// 最后一个测试的完成事件
.on('complete', function() {
  console.log('Fastest is ' + this.filter('fastest').map('name'));
})
// 是否异步运行
.run({ 'async': true });

执行结果如下所示:

for#Array x 398,690 ops/sec ±0.58% (92 runs sampled)
forEach#Array x 94,419 ops/sec ±40.29% (88 runs sampled)
forIn#Array x 6,170 ops/sec ±2.58% (90 runs sampled)
forOf#Array x 238,086 ops/sec ±1.47% (93 runs sampled)
map#Array x 26,244 ops/sec ±17.69% (86 runs sampled)
Fastest is for#Array

Ops/sec: 代表以每秒钟执行代码的次数

±17.69%:  方差,波动越小,数据越稳定。方差的稳定性也和抽样数也会有影响,一般来说,抽样样本越多,方差波动越小,数据越稳定。

88 runs sampled :运行88个抽样

从以上返回的结果来看,数组遍历的时候性能从高到低的依次是:

For > for of > forEach > map > for in

结论:

这只是一个大概的测试结果,影响测试的结果也包括运行数据的大小,运行抽样数据的大小等因素。但是这也可以基本反映出它们各自的一个性能。


 


相关文章
|
7月前
|
JavaScript 前端开发 API
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
7月前
|
数据采集 JavaScript 前端开发
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
用array.filter()来实现数据筛选、数据清洗和链式调用,相对于for循环更加清晰,语义化强,能显著提升代码的可读性和可维护性。博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
12月前
|
自然语言处理 前端开发 JavaScript
🛠️ JavaScript数组操作指南:20个精通必备技巧🚀
本文详细介绍了 JavaScript 中的 20 个高效数组操作技巧,涵盖了从基本的添加、移除元素,到数组转换和去重等高级操作。强调了不可变性的重要性,提供了清晰的代码示例,帮助开发者编写更整洁和高效的代码。无论是新手还是经验丰富的开发者,这些技巧都将显著提升您的编码能力,使您在项目中更具竞争力。
188 2
|
12月前
|
JavaScript 前端开发 测试技术
JS都有哪些操作数组的方法
JS都有哪些操作数组的方法
350 3
|
12月前
|
JavaScript
js删除数组中已知下标的元素
js删除数组中已知下标的元素
283 4
|
12月前
|
JavaScript 前端开发 Java
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
106 5
|
12月前
|
缓存 JavaScript 前端开发
JavaScript中数组、对象等循环遍历的常用方法介绍(二)
JavaScript中数组、对象等循环遍历的常用方法介绍(二)
158 1
|
12月前
|
JavaScript 前端开发 索引
探索JavaScript数组:基础
探索JavaScript数组:基础
81 3
|
12月前
|
JavaScript 前端开发 索引
JS 删除数组元素( 5种方法 )
JS 删除数组元素( 5种方法 )
588 1
|
JavaScript 前端开发
如何在JS中声明一个数组
如何在JS中声明一个数组
225 0

热门文章

最新文章