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

结论:

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


 


相关文章
|
24天前
|
JavaScript 前端开发 索引
JS遍历数组里数组下的对象,根据数组中对象的某些值,组合成新的数组对象
这篇文章介绍了如何在JavaScript中遍历数组里数组下的对象,并根据对象的某些属性值组合成一个新的数组对象。主要内容包括使用ES6的`for...of`循环来遍历数组对象,然后根据需要提取对象中的属性值,并将它们放入新的对象中,最终形成一个新的对象数组以供使用。
|
20天前
|
前端开发 JavaScript 开发者
【前端开发者的福音】彻底改变你编码习惯的神奇数组迭代技巧——从基础到进阶,解锁 JavaScript 数组迭代的N种姿势!
【8月更文挑战第23天】在Web前端开发中,数组是JavaScript中最常用的数据结构之一,掌握高效的数组迭代方法至关重要。本文详细介绍了多种数组迭代技巧:从基础的`for`循环到ES6的`for...of`循环,再到高阶方法如`forEach`、`map`、`filter`、`reduce`及`some`/`every`等。这些方法不仅能提高代码的可读性和维护性,还能有效优化程序性能。通过具体的示例代码,帮助开发者更好地理解和运用这些迭代技术。
24 0
|
9天前
|
JavaScript 前端开发
JavaScript基础知识-数组的遍历
关于JavaScript数组遍历基础知识的文章。
20 2
JavaScript基础知识-数组的遍历
|
9天前
|
JavaScript 前端开发
JavaScript基础知识-数组的练习
关于JavaScript基础知识中数组操作的练习,主要介绍了如何从一个包含Person对象的数组中过滤出成年人(年龄达到18岁及以上)并将他们放入一个新的数组中。
18 1
JavaScript基础知识-数组的练习
|
9天前
|
JavaScript 前端开发
JavaScript基础知识-数组的常用方法
关于JavaScript基础知识-数组的常用方法。
9 1
JavaScript基础知识-数组的常用方法
|
9天前
|
JavaScript 前端开发 索引
JavaScript基础知识-数组基于索引访问
关于JavaScript数组基于索引访问的基础知识介绍。
10 1
JavaScript基础知识-数组基于索引访问
|
9天前
|
JavaScript 前端开发
JavaScript基础知识-数组的定义方式
本文介绍了JavaScript中数组的多种定义方式。
9 1
JavaScript基础知识-数组的定义方式
|
4天前
|
存储 JavaScript 前端开发
JS中的数组有哪些常用操作函数和属性
【9月更文挑战第7天】JS中的数组有哪些常用操作函数和属性
8 1
|
13天前
|
JavaScript 前端开发 UED
JavaScript代码技巧大分享,在数组中去重元素
本文介绍了一系列实用的JavaScript函数,包括将内容复制到剪贴板、获取鼠标选中内容、打乱数组顺序、颜色值转换(RGBA与十六进制)、计算平均值、判断奇偶数、数组去重、检查空对象、反转字符串、计算日期间隔、首字母大写、生成随机字符串和随机数等,帮助提升网站的用户体验和功能丰富性。
19 4
|
14天前
|
JavaScript 前端开发 索引
JS中常用的数组迭代方法(filter,forEach,map,every,some,find,findIndex)
这段代码和说明介绍了JavaScript中数组的一些常用方法。函数接收三个参数:`item`(数组项的值)、`index`(项的位置,可选)和`array`(数组本身,可选)。示例展示了如何使用`filter()`过滤非空项、`forEach()`遍历数组、`map()`处理并返回新数组、`every()`检查所有元素是否满足条件、`some()`检查是否存在满足条件的元素、`find()`获取首个符合条件的元素值以及`findIndex()`获取其索引位置。这些方法都不会修改原数组。
JS中常用的数组迭代方法(filter,forEach,map,every,some,find,findIndex)