forEach与for循环区别


一 ❀ 引

先来看一段代码:

let arr = [1, 2];
arr.forEach((item, index) => {
    arr.splice(index, 1);
    console.log(11111); //输出几次?
});
console.log(arr) //?

let arr1 = [1, 2];
for (var i = 0; i < arr1.length; i++) {
    arr1.splice(i, 1);
    console.log(11111); //输出几次?
}
console.log(arr1) //?

请问,这段代码执行完毕后arr输出为多少?循环体内的console操作会执行几次?

二 ❀ forEach参数

forEach有的也叫增强for循环,forEach其实是for循环的一个特殊简化版。

与for循环一样,forEach也属于完整遍历数组的方法,并会对数组每项元素执行提供的回调函数,一个完整的forEach应该是这样,如下:

arr.forEach(function(self,index,arr){

},this);

self:数组当前遍历的元素,默认从左往右依次获取数组元素。

index:数组当前元素的索引,第一个元素索引为0,依次类推。

arr:当前遍历的数组。

this:回调函数中this指向。

我们来看个简单的forEach例子,加强对于这四个参数的印象:

let arr1 = [1, 2, 3, 4];
let obj = {
    a: 1
};
arr1.forEach(function (self, index, arr) {
    console.log(`当前元素'self'为${self}索引'index'为${index},属于数组'arr'${arr}`);
    console.log(this);
}, obj)

可以看到,arr参数其实就是我们正在遍历的数组,而回调函数中的this指向我们提供的obj。

但若是forEach中使用了箭头函数()=>{},则this指向的不在是当前的回调函数,而是window。

let arr1 = [1, 2, 3, 4];
let obj = {
      a: 1
};
arr1.forEach((self, index, arr) => {
    console.log(`当前元素'self'为${self}索引'index'为${index},属于数组'arr'${arr}`);
    console.log(this);
    console.log(obj);
}, obj)

forEach虽然是for循环的简化版本,但是并不是说foreach就比for更好用,forEach适用于循环次数未知,或者计算循环次数比较麻烦情况下使用效率更高,但是更为复杂的一些循环还是需要用到for循环效率更高。

三 ❀ forEach使用

1.forEach不支持break

大家都知道,在使用for循环时可以使用break跳出循环,比如我希望找到数组中符合条件的第一个元素就跳出循环,这对于优化数组遍历是非常棒的。很遗憾,forEach并不支持break操作,使用break会导致报错。

let arr = [1, 2, 3, 4],
    i = 0,
    length = arr.length;
for (; i < length; i++) {
    console.log(arr[i]); //1,2
    if (arr[i] === 2) {
        break;
    };
};

arr.forEach((self,index) => {
    console.log(self);
    if (self === 2) {
        break; //报错
    };
});

那forEach能不能跳出循环呢?可以。

2.forEach结合try…catch可以跳出循环

try {
    var arr = [1, 2, 3, 4];
    arr.forEach(function (item, index) {
        //跳出条件
        if (item === 3) {
            throw new Error("LoopTerminates");
        }
        //do something
        console.log(item);
    });
} catch (e) {
    if (e.message !== "LoopTerminates") throw e;
};

3.forEach中使用return无效

首先需要确定的,直接在for循环中使用return会报错(函数中使用for可以return),forEach中使用return不会报错,但rerutn并不会生效

let arr = [1, 2, 3, 4];

function forFn(array, num) {
    for (var i = 0; i < array.length; i++) {
        if (array[i] == num) {
            return i
        }
    }
};

function forEachFn(array, num) {
    array.forEach((self, index) => {
        if (self === num) {
            return index;
        };
    });

};

let index1 = forFn(arr, 2);
let index2 = forEachFn(arr, 2);
console.log(index1) // 1
console.log(index2) // undefined

上述代码forEachFn方法 想要找到数字2在数组中的索引,但return并不会起到终止代码运行并返回值的作用。

当然如果我们真的要用return返回某个值,那就只能将return操作放在函数中,而不是在forEach循环中,像这样:

let arr = [1, 2, 3, 4];

function forEachFnNew(array, num) {
    let i = "";
    array.forEach((self, index) => {
        if (self === num) {
            i = index;
        };
    });
    return i;
};

let index3 = forEachFnNew(arr, 2);
console.log(index3) // 1

4.forEach删除自身元素index不会被重置

还记得文章开头的问题吗,那段代码其实只会执行一次,数组也不会被删除干净,这是因为forEach在遍历跑完回调函数后,会隐性让index自增。

5.函数中for循环中break和return区别是什么?

1.break:指的是跳出for循环本身,不再进行之后的循环,但可以执行for循环之外的语句。

function test() {
    for (var i = 1; i <= 5; i++) {
        if (i === 4) {
            break;
        }
        console.log(i); // 分别输出  1,2, 3
    }
    console.log("end"); // 输出end
}

2.return:指的是跳出for循环,且不执行for循环之外的语句,直接跳出当前函数,返回return后的值。

function test() {
    for (var i = 1; i <= 5; i++) {
        if (i === 4) {
            return false;
        }
        console.log(i); // 分别输出  1,2, 3
    }
    console.log("end"); // 未执行
}

3.continue(补充):语句和break语句差不多。不同的是,它不是退出整个循环,而是跳出当前循环,进行下一轮循环(i++)

function test() {
    for (var i = 1; i <= 5; i++) {
        if (i === 4) {
            continue;
        }
        console.log(i); // 分别输出  1,2, 3 5
    }
    console.log("end"); // 输出end
}

四 ❀ for与forEach的区别

  1. for循环可以使用break跳出循环,但forEach不能。
  2. for循环可以控制循环起点(i初始化的数字决定循环的起点),forEach只能默认从索引0开始。
  3. for循环过程中支持修改索引(修改 i),但forEach做不到(底层控制index自增,我们无法左右它)。

五 ❀扩展 forEach与map的区别

相同点:

  1. 都是循环遍历数组中的每一项;
  2. 每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(素引值),arr(原数组)。
  3. 匿名函数中的this都是指向window。
  4. 只能遍历数组。

不同点:

  1. map()会分配内存空间存储新数组并返回,forEach()不会返回数据;
  2. forEach()允许callback更改原始数组的元素。map()返回新的数组。

文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录