写点什么

面试官问我 JS 中 foreach 能不能跳出循环

  • 2022 年 9 月 30 日
    广东
  • 本文字数:1464 字

    阅读完需:约 5 分钟

当年懵懂无知的我被问到这个问题时,脑袋一片空白,因为我一度认为forEach可能只是为了方便书写所创造出来的语法糖,在业务代码中也经常使用,但没有思考过它存在的问题,本文旨在记录自己的心路历程,抛砖引玉,如果对你有所帮助那就更好啦。


那么回到标题,首先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};
复制代码


那么可不可以认为,forEach可以跳出循环,使用抛出异常就可以了?这点我认为仁者见仁智者见智吧,在forEach的设计中并没有中断循环的设计,而使用try-catch包裹时,当循环体过大性能会随之下降,这是无法避免的,所以抛出异常可以作为一种中断forEach的手段,但并不是为解决forEach问题而存在的银弹。


再次回归到开头写的那段伪代码,对它进行一些优化,在真正的 for 循环中加入对传入函数的判断:


// 为避免争议此处不覆写原有forEach函数Array.prototype.myForEach = 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.myForEach(x => { if (x === 'stop') return false console.log(x); // 输出 0 1 后面不输出});
// return即为continue:arr.myForEach(x => { if (x === 'stop') return console.log(x); // 0 1 3 4});
复制代码


文档中还提到 forEach 需要一个同步函数,也就是说在使用异步函数Promise作为回调时会发生预期以外的结果,所以forEach还是需要慎用。


当然,用简单的for循环去完成一切事情也不失为一种办法,代码首先是写给人看的,附带在机器上运行的作用forEach在很多时候用起来更加顺手,但也务必在理解 JS 如何设计这些工具函数的前提下来编写我们的业务代码。


我们可以在遍历数组时使用for..of..,在遍历对象时使用for..in..,而官方也在forEach文档下列举了其它一些工具函数,这里不做过多展开:


Array.prototype.find()Array.prototype.findIndex()Array.prototype.map()Array.prototype.filter()Array.prototype.every()Array.prototype.some()
复制代码


如何根据不同的业务场景,选择使用对应的工具函数来更有效地处理业务逻辑,才是我们真正应该思考的,或许这也是面试当中真正想考察的吧。https://juejin.cn/post/6971972782292729886



发布于: 刚刚阅读数: 4
用户头像

公众号:品味前端 2022.09.22 加入

一介前端,卖码为生。很惭愧,只希望在学习和分享的道路上能做一点微小的贡献。

评论

发布
暂无评论
面试官问我 JS 中 foreach 能不能跳出循环_JavaScript_茶无味的一天_InfoQ写作社区