JS面试题之forEach能否跳出循环详解

当年懵懂无知的我被问到这个问题时,脑袋一片空白,当然也没答对,一直以来我对forEach都有一种错误的理解,由于它比原始的for循环简洁许多,导致我一度认为那是为了方便书写所创造出来的语法糖,在业务中也经常使用,但从没考虑过这种方式存在的问题。

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函数。

那么回到标题,首先forEach是不能使用任何手段跳出循环的,为什么呢?我们知道forEach接收一个函数,它一般有两个参数,第一个是循环的当前元素,第二个是该元素对应的下标,我们手动实现一下:

Array.prototype.myForEach = function (fn) {
    for (let i = 0; i < this.length; i++) {
        fn(this[i], i, this);
    }
}

forEach是不是真的这么实现我无从考究,但是以上这个简单的伪代码确实满足forEach的特性,而且也很明显就是不能跳出循环,因为你根本没有办法操作到真正的for循环体。

后来经过查阅文档,发现官方对forEach的定义根本不是我认为的语法糖,它的标准说法是forEach为每个数组元素执行一次你所提供的函数。到这里我的思路逐渐明朗,官方文档也有这么一段话:

除抛出异常之外,没有其他方法可以停止或中断循环。如果您需要这种行为,则该forEach()方法是错误的工具。

使用抛出异常来跳出foreach循环

let arr = [0, 1, "stop", 3, 4];
try {
    arr.forEach(element => {
        if (element === "stop") {
            throw new Error("forEachBreak");
        }
        console.log(element); // 输出 0 1 后面不输出
    });
} catch (e) {
    console.log(e.message); // forEachBreak
};

当然,使用try-catch包裹时,当循环体过大性能会随之下降,这是无法避免的,所以抛出异常并不是解决forEach问题的银弹,我们回归到开头写的那段伪代码,我们对它进行一些优化,在真正的for循环中加入对传入函数的判断:

Array.prototype.forEach = function (fn) {
    for (let i = 0; i < this.length; i++) {
        let ret = fn(this[i], i, this);
        if (typeof ret !== "undefined" && (ret == null || ret == false)) break;
    }
}

这样的话自然就能根据return值来进行循环跳出啦:

let arr = [0, 1, "stop", 3, 4];

arr.forEach(element => {
    if (element === 'stop') return false
    console.log(element); // 输出 0 1 后面不输出
});

console.log('return即为continue:');
arr.forEach(element => {
    if (element === 'stop') return
    console.log(element); // 0 1 3 4
});

文档中还提到forEach需要一个同步函数,也就是说在使用异步函数或Promise作为回调时会发生预期以外的结果,所以forEach还是需要慎用或者不要使用,当然这并不意味着项目开发中要一直用简单的for循环去完成一切事情,我们可以在遍历数组时使用for..of..,在遍历对象时使用for..in..,而官方也在forEach文档下列举了其它一些工具函数:

Array.prototype.find()
Array.prototype.findIndex()
Array.prototype.map()
Array.prototype.filter()
Array.prototype.every()
Array.prototype.some()

根据不同的业务场景,选择使用对应的工具函数来更有效地处理业务逻辑,至于forEach,我想就从此相忘于江湖吧。

总结

到此这篇关于JS面试题之forEach能否跳出循环的文章就介绍到这了,更多相关JS forEach跳出循环内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-06-09

JavaScript使用类似break机制中断forEach循环的方法

JavaScript数组对象,有一个forEach方法,可枚举每一个数组元素,但并不支持类似for循环的break语法,中断循环: [1,2,3].forEach(function(item) { // if(!item) break; 不支持 }); 解决办法,可抛出一个特殊异常,来中断forEach循环,原理: var BreakException = {}; try { [1, 2, 3].forEach(function(el) { console.log(el); if (el ===

js的for in循环和java里foreach循环的区别分析

本文实例分析了js的for in循环和java里foreach循环的区别.分享给大家供大家参考.具体分析如下: js里的for in循环定义如下: 复制代码 代码如下: for(var variable in obj) { ... } obj可以是一个普通的js对象或者一个数组.如果obj是js对象,那么variable在遍历中得到的是对象的属性的名字,而不是属性对应的值.如果obj是数组,那么variable在遍历中得到的是数组的下标. 遍历对象实验: 复制代码 代码如下: var v = {

js中forEach,for in,for of循环的用法示例小结

本文实例讲述了js中forEach,for in,for of循环的用法.分享给大家供大家参考,具体如下: 一.一般的遍历数组的方法: var array = [1,2,3,4,5,6,7]; for (var i = 0; i < array.length; i++) { console.log(i,array[i]); } 二.用for in的方遍历数组,得到的是索引 var array = [1,2,3,4,5,6,7]; for(let index in array) { console

javascript forEach通用循环遍历方法

复制代码 代码如下: var forEach = (function(){ //数组与伪数组的遍历 var _Array_forEach = function (array, block, context) { if (array == null) return; //对String进行特殊处理 if(typeof array == 'string'){ array = array.split(''); } var i = 0,length = array.length; for (;i < l

Javascript数组循环遍历之forEach详解

1.js 数组循环遍历. 数组循环变量,最先想到的就是 for(var i=0;i<count;i++)这样的方式了. 除此之外,也可以使用较简便的forEach 方式 2.forEach函数. Firefox 和Chrome 的Array 类型都有forEach的函数.使用如下: <!--Add by oscar999--> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> &l

JS forEach跳出循环2种实现方法

假设当我们只需知道某个数组有没有某个属性,如果找到了直接跳出循环,省略掉剩下的循环步骤是较优化的操作,但是for中是可以利用break跳出循环,但break在forEach中无效,那么forEach能不能跳出循环呢?当然是可以. 1.正常for循环break跳出循环 let strArr = ['a', 'b', 'c', 'd'], i = 0, length = strArr.length; for (; i < length; i++) { console.log(strArr[i]);/

详谈js中标准for循环与foreach(for in)的区别

js中遍历数组的有两种方式 var array=['a'] //标准的for循环 for(var i=1;i<array.length;i++){ alert(array[i]) } //foreach循环 for(var i in array){ alert(array[i]) } 正常情况下上面两种遍历数组的方式结果一样.首先说两者的第一个区别 标准的for循环中的i是number类型,表示的是数组的下标,但是foreach循环中的i表示的是数组的key是string类型,因为js中一切皆为

全面解析JavaScript里的循环方法之forEach,for-in,for-of

JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能. JavaScript诞生已经有20多年了,我们一直使用的用来循环一个数组的方法是这样的: for (var index = 0; index < myArray.length; index++) { console.log(m

php解析字符串里所有URL地址的方法

本文实例讲述了php解析字符串里所有URL地址的方法.分享给大家供大家参考.具体如下: <?php // $html = the html on the page // $current_url = the full url that the html came from //(only needed for $repath) // $repath = converts ../ and / and // urls to full valid urls function pageLinks($ht

Javascript里的两种使用正则的方法

在Javascript里,有两种使用正则的方法,一是创建一个正则表达式的实例,而是使用String对象里的正则表达相关的方法. 正则表达式对象 两种创建方法 var my_regex=/[a-z]+/g;  var my_regex=new ("[a-z]+","g"); 方法 exec(string),对string进行正则处理,并返回匹配结果.  test(string),测试string是否含有匹配结果 字符串对象中的正则 方法 match(pattern) 

javascript实现图片循环渐显播放的方法

本文实例讲述了javascript实现图片循环渐显播放的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: <html> <title>图片的循环渐显播放效果代码</title> <head> <!--1.将下面的代码插入到HEML的<head></head>之间: --> <script language=javaScript> <!--// sandra0 = new Image()

javascript实现图像循环明暗变化的方法

本文实例讲述了javascript实现图像循环明暗变化的方法.分享给大家供大家参考.具体如下: <SCRIPT language=JavaScript> var d=0 function JM_fade(ob){ if (d==0) {ob.filters.alpha.opacity+=1} else {ob.filters.alpha.opacity-=1} if (ob.filters.alpha.opacity==100){d=1;} else if (ob.filters.alpha.

javascript使用for循环批量注册的事件不能正确获取索引值的解决方法

本文实例讲述了javascript使用for循环批量注册的事件不能正确获取索引值的解决方法.分享给大家供大家参考.具体分析如下: 可能不少朋友会遇到一个问题,那就是当使用for循环批量注册事件处理函数,然后最后通过事件处理函数获取当前元素的索引值的时候会失败,先看一段代码实例: 复制代码 代码如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name=&q

在Javascript里访问SharePoint列表数据的实现方法

在SharePoint2010里有了很好的解决方案(详见拙文SharePoint客户端编程系列http://www.jb51.net/article/27198.htm),但是在SharePoint2007里就没那么好用,具体问题具体分析,本文要解决的是如何在JavaScript里通过WebService访问SharePoint数据的问题. 首先需要从此处(http://darrenjohnstone.net/download/12)下载JavaScript API包 引用次JS,里面有两个库,

JavaScript解析JSON格式数据的方法示例

本文实例讲述了JavaScript解析JSON格式数据的方法.分享给大家供大家参考,具体如下: 1.使用JavaScript提供的eval()函数 function JsonText1() { var strJSON = "{'Name':'Kevin','Age':'23'}"; //得到的JSON var obj = eval("(" + strJSON + ")"); //转换后的JSON对象 alert(obj.Name); } 2.使用

JavaScript 模块的循环加载实现方法

"循环加载"(circular dependency)指的是,a脚本的执行依赖b脚本,而b脚本的执行又依赖a脚本. // a.js var b = require('b'); // b.js var a = require('a'); 通常,"循环加载"表示存在强耦合,如果处理不好,还可能导致递归加载,使得程序无法执行,因此应该避免出现. 但是实际上,这是很难避免的,尤其是依赖关系复杂的大项目,很容易出现a依赖b,b依赖c,c又依赖a这样的情况.这意味着,模块加载机

JavaScript实现解析INI文件内容的方法

本文实例讲述了JavaScript实现解析INI文件内容的方法.分享给大家供大家参考,具体如下: .ini 是Initialization File的缩写,即初始化文件,ini文件格式广泛用于软件的配置文件. INI文件由节.键.值.注释组成. 根据node.js版本的node-iniparser改写了个JavaScript函数来解析INI文件内容,传入INI格式的字符串,返回一个json object. function parseINIString(data){ var regex = {