JS实用功能-10、遍历数组for vs for-in vs forEach() vs for-of


下面给大家讲讲JS中常用的四种数组遍历的方法,并做一下对比。

四种常用的方法如下:

let someArray = [1,2,3,4];
//for循环
for(let i = 0; i < someArray.length; i++){
  const elem = someArray[i];
  //...
}
//for-in循环
for (const key in someArray) {
    console.log(key);
}
//数组原生 forEach
someArray.forEach((element, index) => {
    console.log(element, index);
});
//for-of循环
for (const iterator of someArray) {
    console.log(iterator);
}

但for-of是最佳选择,下面我们来具体分析一下。

一、for循环

for是JavaScript中的普通循环。它已存在于ECMAScript 1中。此for循环记录以下各项的每个元素的索引和值arr:
const arr = ['a', 'b', 'c'];
arr.prop = 'property value';
for(let i = 0; i < arr; i++){
  const elem = arr[i];
  console.log(elem, i);
}
//输出:
//0, 'a'
//1, 'b'
//2, 'c'

说说此循环的优缺点:

它非常通用,但是当我们要做的是遍历数组时,也很麻烦。 如果我们不想从第一个Array元素开始循环,它仍然很有用。没有其他的循环机制可以让我们做到这一点。

二、for-in循环

for-in循环跟为for循环年代一样久远,在ECMAScript1中就有for-in循环记录。
//...
for (const key in arr) {
    console.log(key);
}
//输出:
//'0'
//'1'
//'2'
//'prop'
for-in 不是遍历数组的好选择: 1.它访问属性键,而不是值。 2.作为属性键,数组元素的索引是字符串,而不是数字。 3.它访问所有可枚举的属性键(自己的和继承的),而不仅仅是Array元素的那些。 for-in访问继承的属性确实有一个用例:遍历对象的所有可枚举属性。但是即使在这里,我还是希望手动遍历原型链,因为您拥有更多控制权。

三、数组的forEach方法

考虑到两者for都不for-in是特别适合循环遍历数组,ECMAScript 5中引入了一个辅助方法Array.prototype.forEach():
arr.forEach((elem, index) => {
    console.log(elem, index);
});
//输出:
//'a', 0
//'b', 1
//'c', 2
此方法确实很方便:它使我们无需执行大量操作即可访问Array元素和Array元素索引。箭头函数(在ES6中引入)使该方法在语法上更加优雅。 forEach函数的主要缺点: 1.您不能await在这种循环的“主体”中使用。 2.您不能.forEach()提早结束循环。在for循环中,我们可以使用break。

三(1)、可以提前结束的forEach方法

有一种解决方法,如果您要使用类似循环.forEach()并提早结束:.some()还循环所有Array元素,并在其回调返回真值时停止。
const color = ['red', 'green', 'blue'];
color.some((elem, index) => {
    if(index > 2){
        return true; //结束循环
    }
    console.log(elem);
    //此回调隐式返回“undefined”,这是一个错误的值。因此,循环仍在继续。
});
//输出:
//'red'
//'green'
可以说,这是对.some()的滥用,我不确定理解此代码(与for-of和相比break)有多么容易。

四、for-of循环

ES6中的循环法。
for (const elem of arr) {
    console.log(elem);
}
//输出:
//'a'
//'b'
//'c'
for-of 对于遍历数组非常有效: 1.遍历数组元素。 2.我们可以使用await。 3.我们甚至可以将–break和continue用于外部范围.

四(1)、for-of和迭代对象

for-of的另一个好处是,我们不仅可以遍历数组,还可以遍历任何可迭代对象,例如遍历Maps:
const myMap = new Map()
    .set(false, 'no')
    .set(true, 'yes');
for (const elem of myMap) {
    console.log(key, value);
}
//输出:
//false, 'no'
//true, 'yes'
迭代myMap产生[key,value]对,我们对其进行解构以直接访问每个对的组件。

四(2)、for-of和数组索引

Array方法.keys()返回Array的索引上的可迭代对象:
const snacks = ['巧克力', '草莓', '香草'];
for (const index of snacks.keys) {
    console.log(index);
}
//输出:
//0
//1
//2

四(3)、for-of和数组的entries方法

Array方法.entries()返回[index,value]对上的可迭代对象。如果使用for-of此方法并对其进行销毁,则可以方便地访问索引和值:
//...
for (const [index, value] of snacks.entries) {
    console.log(index, value);
}
//输出:
//0, '巧克力'
//1, '草莓'
//2, '香草'
四种循环机制之间的性能差异通常应该无关紧要。但是可以从方法的限制和多用方面考虑使用。