JS-为什么forEach无法跳出循环

foreach.jpg

很久之前就发现使用forEach循环数组时是无法跳出循环的,break和return都不生效。数组中的所有元素都会被遍历。今天花时间研究了一下深层的原理。有不对的地方欢迎指正。

1.举个例子

var list = [0,1,2,3,4,5,6,7,8,9];
list.forEach(function(item){
    console.log(item);
    if (item > 3 ){
        return;
    }
});

输出结果是0,1,2,3,4,5,6,7,8,9。并没有在大于3的时候终止循环。

如果把return替换为break会报错:Uncaught SyntaxError: Illegal break statement

2.forEach使用说明

参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach?v=example

arr.forEach(function callback(currentValue, index, array) {
    //your iterator
}[, thisArg]);

currentValue --- 当前处理的元素
index --- 当前处理元素的索引
array ---forEach应用的数组

有一段提示写到了在forEach中break和return的用法。原文如下:

There is no way to stop or break a forEach()loop other than by throwing an exception. If you need such behavior, theforEach()method is the wrong tool. Use a plain loop instead. If you are testing the array elements for a predicate and need a Boolean return value, you can useevery() or
some() instead. If available, the new methodsfind() or findIndex() can be used for early termination upon true predicates as well.

意思就是说在forEach中使用break和return是错误的,如果希望使用break或者return请使用every或者some函数。

3.为什么不能使用return和break

在V8的源码里找了又找也没有找到forEach函数的源码,从其他实现的forEach中也能发现一些端倪。

Array.prototype.myEach = function(callback) {
    for (var i = 0; i < this.length; i++)
        callback(this[i], i, this);
};

猜测js的实现源码应该也是这种原理,我们传入的function是这里的回调函数。在回调函数里面使用break肯定是非法的,因为break只能用于跳出循环,而我们的回调函数不是循环体。

在回调函数中使用return,只是将结果返回到上级函数,也就是这个for循环中,并没有结束for循环,所以return也是无效的。

举个例子实际说明一下:

var subFunction = function(callback){
    for (var i = 0;i < 10; i++){
        callback(i);
        console.log(i);
    }
}

var func = function(i){
    if(i>3){
        return
    }else{
        console.log('callback i =' + i);
    }
}

subFunction(func);

我们在forEach中使用return就如同func中的return一样,只是在回调函数中执行了return,并不能影响到上级函数中的for循环,自然不会中断for循环的运行了。

4.for vs forEach

需要遍历数组的时候使用哪个好呢?
forEach的优点是写法简单,避免了下标溢出的情况。
for的优点是性能比forEach好,可以使用break和return。
大家根据实际情况择优使用吧。

如有理解不正确的地方,欢迎指正~~