点击查看视频课程: 如何跳出 forEach 循环 https://www.bilibili.com/video/av46607656
我们都知道, 在使用 for 循环的时候可以使用 break 或者 return 语句来结束 for 循环 (return 直接结束函数), 但是如果使用 forEach 循环如何跳出循环呢?
尝试使用 break 和 return
首先尝试一使用 return 语句 ---- 木有效果
使用 return:
- [1,2,3,4,5].forEach(item=>{
- if(item===2){
- return
- }
- console.log(item); // 1 3 4 5
- })
再尝试一下使用 break 语句 ---- 报错
使用 break:
- [1,2,3,4,5].forEach(item=>{
- if(item===2){
- break
- }
- console.log(item); //Illegal break statement...
- })
MDN 给出的官方解释
为什么会出现这样的情况? 先看一下官方文档的说明.
MDN 文档上明确说明 forEach 循环是不可以退出的.
引自 MDN
There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool.
注意: 没有办法中止或者跳出 forEach() 循环, 除了抛出一个异常. 如果你需要这样, 使用 forEach() 方法是错误的.
若你需要提前终止循环, 你可以使用:
简单循环
for...of 循环
- Array.prototype.every()
- Array.prototype.some()
- Array.prototype.find()
- Array.prototype.findIndex()
探究为什么 break 和 return 不行
先看看为什么 return 没有效果, break 报错
forEach 的实现方式用代码表示出来可以写成如下的结构
- // 源码解析
- const arr = [1, 2, 3, 4, 5];
- for (let i = 0; i <arr.length; i++) {
- const rs = (function(item) {
- console.log(item);
- if (item> 2) return false;
- })(arr[i])
- }
使用 return 语句相当于在每个自执行函数中将返回值复制给 rs, 但是实际对整个函数并没有影响. 而使用 break 语句报错是因为, 在 JS 的解释器中 break 语句是不可以出现在函数体内的.
如何变通跳出 forEach 循环
MDN 官方推荐的方法
使用 some 和 every:
every 在碰到 return false 的时候, 中止循环. some 在碰到 return true 的时候, 中止循环.
使用 some 和 every 的代码如下:
- var a = [1, 2, 3, 4, 5]
- a.every(item=>{
- console.log(item); // 输出: 1,2
- if (item === 2) {
- return false
- } else {
- return true
- }
- })
- var a = [1, 2, 3, 4, 5]
- a.some(item=> {
- console.log(item); // 输出: 1,2
- if (item === 2) {
- return true
- } else {
- return false
- }
- })
其他方法
1. 使用 for 循环或者 for in 循环代替
2. 使用 throw 抛出异常
- try {
- [1, 2, 3, 4, 5].forEach(function(item) {
- if (item=== 2) throw item;
- console.log(item);
- });
- } catch (e) {}
3. 使用判断跑空循环
- var tag;
- [1, 2, 3, 4, 5].forEach(function(item){
- if(!tag){
- console.log(item);
- if(item===2){
- tag=true;
- }
- }
- })
这样做有两个问题, 第一个问题, 全局增加了一个 tag 变量, 第二个问题, 表面上看是终止了 forEach 循环, 但是实际上循环的次数并没有改变, 只是在不满足条件的时候 callback 什么都没执行而已.
先来解决第一个问题, 如何删除全局下新增的 tag 变量 . 实际上 forEach 还有第二个参数, 表示 callback 的执行上下文, 也就是在 callback 里面 this 对应的值. 因此我们可以将上下文设置成空对象, 这个对象自然没有 tag 属性, 因此访问 this.tag 的时候会得到 undefined
不增加全局变量的代码如下:
- [1, 2, 3, 4, 5].forEach(function(item){
- if(!this.tag){
- console.log(item); // 1 2
- if(item===2){
- this.tag=true;
- }
- }
- },{})
4. 修改索引
- var array=[1, 2, 3, 4, 5]
- array.forEach(item=>{
- if (item == 2) {
- array = array.splice(0);
- }
- console.log(item); // 1 2
- })
关于修改索引终止循环的讲解:
forEach 的执行细节
1. 遍历的范围在第一次执行 callback 的时候就已经确定, 所以在执行过程中去 push 内容, 并不会影响遍历的次数, 这和 for 循环有很大区别, 下面的两个案例一个会造成死循环一个不会
- var arr=[1,2,3,4,5]
- // 会造成死循环的代码
- for(var i=0;i<arr.length;i++){
- arr.push('a')
- }
下面的这行代码则不会造成死循环
arr.forEach(item=>arr.push('a'))
2. 如果已经存在的值被改变, 则传递给 callback 的值是 forEach 遍历到他们那一刻的值.
- var arr=[1,2,3,4,5];
- arr.forEach((item,index)=>{
- console.log(`time ${index}`)
- arr[index+1]=`${index}a`;
- console.log(item)
- })
3. 已删除的项不会被遍历到. 如果已访问的元素在迭代时被删除了 (例如使用 shift()), 之后的元素将被跳过.
- var arr=[1,2,3,4,5];
- arr.forEach((item,index)=>{
- console.log(item)
- if(item===2){
- arr.length=index;
- }
- })
在满足条件的时候将后面的值截掉, 下次循环的时候找不到对应的值, 循环就结束了, 这就是修改索引能够中止 forEach 循环的原因.
但是这样操作会破坏原始的数据, 因此我们可以使用一个小技巧, 即将数组从 0 开始截断, 然后重新赋值给数组, 也就是使用 array=array.splice(0).
关于 冰山工作室
QQ 群: 600633658
加入我们, 前端大佬在线答疑解惑, 带你深入了解前端知识.
视频课程网盘地址 提取码 558x
学习资料将在 冰山工作室 各平台官方账户同步更新, 直通车
冰山工作室官网 http://www.bingshangroup.com/#/
知乎 https://zhuanlan.zhihu.com/bingshan
掘金 https://juejin.im/user/5b7fd761e51d4538c411dc93
微博 https://weibo.com/qqkillqq?is_hot=1
前端网
思否 https://segmentfault.com/u/bingshangroup
简书 https://www.jianshu.com/u/4e2e5c6a5983
新闻头条
喜马拉雅 https://www.ximalaya.com/jiaoyu/3740790/
来源: http://www.qdfuns.com/article/21292/2b047241d804264bbec566f8d4324649.html