# 了解一下各种数组遍历的差异

# 简单测试一下

const n = 1000000
const arr = new Array(n).fill(0)

console.log(n, '条数据遍历:')
// 普通for循环
let start = Date.now()
for (let i = 0; i < arr.length; i++) {}
console.log('普通for:', Date.now() - start, 'ms')

// 加强for循环
start = Date.now()
for (let i = 0, j = arr.length; i < j; i++) {}
console.log('加强for:', Date.now() - start, 'ms')

// 倒序for循环
start = Date.now()
for (let i = arr.length; i--; ) {}
console.log('倒序for:', Date.now() - start, 'ms')

// forEach
start = Date.now()
arr.forEach(() => {})
console.log('forEach:', Date.now() - start, 'ms')

// map
start = Date.now()
arr.map(() => {})
console.log('map:', Date.now() - start, 'ms')

// for in
start = Date.now()
for (let i in arr) {
}
console.log('for in:', Date.now() - start, 'ms')

// for of
start = Date.now()
for (let i of arr) {
}
console.log('for of:', Date.now() - start, 'ms')

// for-in是最慢的,倒序for是最快的
// 经简单测试:10万条数组相差时间不大,100万条以上时间差距明显
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
10 万条数据 100 万条数据 1000 万条数据
普通 for 2ms 3ms 7ms
加强 for 1ms 2ms 7ms
倒序 for 0ms 3ms 7ms
forEach 2ms 11ms 106ms
map 4ms 19ms 192ms
for in 11ms 166ms 2668ms
for of 6ms 40ms 159ms

# 进一步分析

# 加强 for

persons.length缓存到变量len中,这样每次循环时就不会再读取数组的长度。

# 倒序 for

从后向前,直到 i === 0 为止。这种方式不仅去除了每次循环中读取数组长度的操作,而且只创建了一个变量 i。

# forEach

forEach 方法对数组的每个元素执行一次提供的 callback 函数,forEach 是一个数组方法,可以用来把一个函数套用在一个数组中的每个元素上,forEach为每个数组元素执行 callback 函数只可用于数组,遍历一个数组让数组每个元素做一件事情

那些已删除(使用 delete 方法等情况)或者**未初始化的项(如 empty)**将被跳过(但不包括那些值为 undefined 的项)(例如在稀疏数组上);

不像 map() 或者 reduce() ,它总是返回 undefined 值,并且不可链式调用。典型用例是在一个链的最后执行副作用。

# map

map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。

callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。让数组通过某种计算产生一个新数组,影射成一个新的数组

# for in

一般会使用for-in来遍历对象的属性的,不过属性需要 enumerable,才能被读取到. for-in 循环只遍历可枚举属性。

一般常用来遍历对象,包括非整数类型的名称和继承的那些原型链上面的属性也能被遍历。

像 Array 和 Object 使用内置构造函数所创建的对象都会继承自 Object.prototype 和 String.prototype 的不可枚举属性就不能遍历了.

# for of

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

只要是一个 iterable 的对象,就可以通过for-of来迭代.

# for-of 和 for-in 的区别

for-in 语句以原始插入顺序迭代对象的可枚举属性。for-in会把继承链的对象属性都会遍历一遍,所以会更花时间.

for-of 语句只遍历可迭代对象的数据。

# 浏览器差异

forEachmapfor infor of 这些ES6+的语法并没有传统的for循环或者while循环快,特别是map方法。

for循环 while循环 for of 循环是可以通过break关键字跳出的,而forEach map这种循环是无法跳出的。

但是随着执行环境和浏览器的不同,这些语法在执行速度上也会出现偏差甚至反转的情况

  1. 谷歌浏览器中ES6+的循环语法会普遍比传统的循环语法慢,但是火狐和 safari 中情况却几乎相反。
  2. 谷歌浏览器的各种循环语法的执行耗时上差距并不大。但map特殊,速度明显比其他几种语法慢,而在火狐和 safari 中却出现了反转,map反而比较快!
  3. 苹果大法好

# 参考

JavaScript 数组遍历方法的对比 (opens new window)

JS 数组循环的性能和效率分析(for、while、forEach、map、for of) (opens new window)

最近更新: 4 小时前