【js】for、forEach、map数组遍历性能比较
先上结果:遍历时间上 for循环遍历 < for…of遍历 < forEach遍历 < for…in遍历 < map遍历
背景
常用的数组遍历方式有很多,
如最经典的for循环
for (var i = 0; i < arr.length; i++) {}
再者有了for…in
for (var i in arr) {}
forEach
arr.forEach(function (i) {});
map
arr.map(function (i) {});
然后ES6有了更为方便的for…of
for (let i of arr) {}
此篇不考虑作用差异,仅对这些方式的性能做一次比较。
注:filter、every、some跟forEach/map相近,不常用所以本次不加入比较。
1.对比方案
本次采用最直观的方式进行对比:通过对高数量级数组的遍历时间进行比较。
1.1 数组arr:
let arr = [];
for (let i = 0; i < 10000000; i++) {
arr[i] = i;
}
console.log(arr); // [0, 1, 2, 3, ... , 9999999]
1.2 对比函数:
function getAverageTime (cb) {
let _start = +new Date();
for (let k = 0; k < 20; k++) {
cb(); // 遍历函数
}
return (+new Date() - _start) / 20 + 'ms'
}
- 其中cb为遍历函数。
我们通过20次求平均值的方式来推算遍历的时间,以此作为比较依据。
2.比较
1.1 经典的for循环遍历
getAverageTime(function () {
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
// ...
}
})
结果:
6.3ms
1.2 for…in遍历
getAverageTime(function () {
for (let i in arr) {
let item = arr[i];
// ...
}
})
结果:
1539.45ms
1.3 forEach遍历
getAverageTime(function () {
arr.forEach(item => {})
})
结果:
190.75ms
1.4 map遍历
getAverageTime(function () {
arr.map(item => {})
})
结果:
2014.65ms
1.5 for…of遍历
getAverageTime(function () {
for (let item of arr) {
// ...
}
})
结果:
129.5ms
*babel转ES5后遍历
for…of是ES6语法,所以日常页面中基本会babel转换,所以需要测试一下转换后的遍历
getAverageTime(function () {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
//...
var item = _step.value;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
});
结果:
105.9ms
(是不是感觉for…of经过Babel转换后的代码很诡异,有兴趣可以去了解下Symbol对象,其实Symbol对象也是ES6所新加的,只是兼容比for…of好些,要兼容低版本手机的话了解一下es-symbol)
3 结果分析
通过对比可知,遍历时间
for循环遍历 < for...of遍历 < forEach遍历 < for...in遍历 < map遍历
3.1 *为何for… in会慢?
因为for … in语法是第一个能够迭代对象键的JavaScript语句,循环对象键({})与在数组([])上进行循环不同,引擎会执行一些额外的工作来跟踪已经迭代的属性。
因此可以大致可以得出以下几点:
- 数据量大时,遍历性能的差距尤为明显;
- for系遍历总体性能好于forEach、map等数组方法
- 你大爷毕竟是你大爷,性能最佳的还是经典的for循环遍历
- forEach性能优于map
- for…of要兼容低版本设备的话还是算了
遍历的性能可以作为以后开发的参考,毕竟数据量不大的时候差异可忽略不计,更多的可以根据实际作用来考虑遍历方式,比方说for系遍历可以break中途退出而forEach/map不行。
*附上考虑变量类型的遍历抽象函数
/**
* @param {Object | Array} array
* @param {Function} func
*/
function eachPlus (array, func) {
if (!array) {
return;
}
let rst = void 0,
type = Object.prototype.toString.call(array).replace(/\[object\s|\]/g, '');
if (type === 'Array') {
for (let i = 0, len = array.length; i < len; i++) {
rst = func(array[i], i);
if (rst === false) { // 实现break中断
break;
}
}
} else if (type === 'Object') {
for (let k in array) {
if (array.hasOwnProperty(k)) {
rst = func(array[k], k);
if (rst === false) {
break;
}
}
}
}
}
// demo
eachPlus([1, 2, 3], item => {
console.log(item);
})
eachPlue({ a: 1, b: 2, c: 3 }, item => {
console.log(item);
})
文本博客地址
有建议或想砸鸡蛋可 -> michealwayne@163.com
来源:CSDN
作者:Micheal_Wayne
链接:https://blog.csdn.net/qq_24357165/article/details/82748976