前言

本文925字,阅读大约需要7分钟。

总括: forEach循环中你不知道的3件事。

自弃者扶不起,自强者击不倒。

正文

你觉得你真的学会用forEach了么?

这是我之前对forEach循环的理解:就是一个普通语义化之后的for循环,可以被break,continue,return

这篇文章将向你展示forEach中你可能不了解的3件事。

1. return不会停止循环

你觉得下面的代码在打印12之后会停止么?

array = [1, 2, 3, 4];
array.forEach(function (element) {
console.log(element); if (element === 2)
return; });
// Output: 1 2 3 4

答案是不会,上述代码会正常打印1,2,3,4。如果你有Java背景,你也许会很诧异,这怎么可能呢?

原因是我们在forEach函数中传了一个回调函数,该回调函数的行为和普通函数一样,我们return操作其实就是普通函数中return。所以并不符合我们预期将forEach循环打断。

MDN官方文档:

注意: 除了抛出异常以外,没有办法中止或跳出 forEach() 循环。如果你需要中止或跳出循环,forEach() 方法不是应当使用的工具。

我们将上述代码改写:

const array = [1, 2, 3, 4];
const callback = function(element) {
console.log(element); if (element === 2)
return; // would this make a difference? no.
}
for (let i = 0; i < array.length; i++) {
callback(array[i]);
}
// Output: 1 2 3 4

这就是上述代码实际的执行思路,return操作只作用于当前的函数,自然不会对for循环产生影响

2. 不能break

下面的代码你觉得会被break掉么?

const array = [1, 2, 3, 4];
array.forEach(function(element) {
console.log(element); if (element === 2)
break;
});
// Output: Uncaught SyntaxError: Illegal break statement

不会,甚至这行代码都不会运行,直接报错了。

那么这段代码如何达到我们原本想达到的效果呢?

用普通for循环就好了:

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

3. 不能continue

下面代码会是跳过2只打印1、3、4吗?

const array = [1, 2, 3, 4];
array.forEach(function (element) {
if (element === 2)
continue; console.log(element);
});
// Output: Uncaught SyntaxError: Illegal continue statement: no surrounding iteration statement

同样不会,和break一样,报错,这行代码之后甚至都不会运行。

怎么达到预期呢?

还是使用普通的for循环来解决:

for (let i = 0; i < array.length; i++) {
if (array[i] === 2)
continue;
console.log(array[i]);
}
// Output: 1 3 4

译者补充

forEach函数的实际运行原理其实是这样的,伪代码如下:

let arr = [1, 2];
arr.forEach(function(ele) {
console.log(ele);
});
// output: 1, 2
// 上面代码等同于
function func(ele) {
console.log(ele);
}
for (let i = 0; i < arr.length; i++) {
func(arr[i])
}
// output: 1, 2

实际上forEach的polyfill实现也是这样的,在forEach函数中执行一个for循环,在for循环里调用回调函数。

因此,像下面代码自然不会符合预期:

let arr = [1, 2];
let sum = 0;
function add(a) {
return a;
}
arr.forEach(async function(ele) {
sum += await add(ele);
});
console.log(sum);
// Output:0

改写如下:

let arr = [1, 2];
let sum = 0;
function add(a) {
return a;
}
for (let i = 0; i < arr.length; i++) {
sum += await add(arr[i]);
}
console.log(sum);
// Output:3

订阅更多文章可关注「前端进阶学习」,回复「666」,获取一揽子前端技术书籍

「译」forEach循环中你不知道的3件事的更多相关文章

  1. 「译」 .NET 6 中 gRPC 的新功能

    gRPC是一个现代的.跨平台的.高性能的 RPC 框架.gRPC for .NET 构建在 ASP.NET Core 之上,是我们推荐的在 .NET 中构建 RPC 服务的方法. .NET 6 进一步 ...

  2. 「译」JUnit 5 系列:条件测试

    原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...

  3. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

  4. 「译」JavaScript 的怪癖 1:隐式类型转换

    原文:JavaScript quirk 1: implicit conversion of values 译文:「译」JavaScript 的怪癖 1:隐式类型转换 译者:justjavac 零:提要 ...

  5. jvm系列(十):如何优化Java GC「译」

    本文由CrowHawk翻译,是Java GC调优的经典佳作. 本文翻译自Sangmin Lee发表在Cubrid上的"Become a Java GC Expert"系列文章的第三 ...

  6. jvm系列(七):如何优化Java GC「译」

    本文由CrowHawk翻译,地址:如何优化Java GC「译」,是Java GC调优的经典佳作. Sangmin Lee发表在Cubrid上的”Become a Java GC Expert”系列文章 ...

  7. iOS 9,为前端世界都带来了些什么?「译」 - 高棋的博客

    2015 年 9 月,Apple 重磅发布了全新的 iPhone 6s/6s Plus.iPad Pro 与全新的操作系统 watchOS 2 与 tvOS 9(是的,这货居然是第 9 版),加上已经 ...

  8. C#在foreach循环中修改字典等集合出错的处理

    C#在foreach循环中修改字典等集合出错:System.InvalidOperationException: Collection was modified; enumeration operat ...

  9. C#不允许在foreach循环中改变数组或集合中元素的值(注:成员的值不受影响)

    C#不允许在foreach循环中改变数组或集合中元素的值(注:成员的值不受影响),如以下代码将无法通过编译. foreach (int x in myArray) { x++; //错误代码,因为改变 ...

随机推荐

  1. 201771010135杨蓉庆 《面对对象程序设计(java)》第八周学习总结

    1.实验目的与要求 (1) 掌握接口定义方法: (2) 掌握实现接口类的定义要求: (3) 掌握实现了接口类的使用要求: (4) 掌握程序回调设计模式: (5) 掌握Comparator接口用法: ( ...

  2. python脚本监听nginx是否运行

    import sys import time import os import logging from logging.handlers import RotatingFileHandler imp ...

  3. Educational Codeforces Round 79 (Rated for Div. 2) - D. Santa's Bot(数论)

    题意:有$n$个孩子,第$i$个孩子有$k[i]$件想要的礼物,第$j$个礼物为$a[i][j]$,现在随机挑一个孩子,从他想要的礼物里面随机挑一个,然后送给另一个孩子$($这个孩子可以和第一个孩子是 ...

  4. springboot2.0集成RestTemplate

    实际集成 获取restTemplate实例,封装方法 package com.quant.api.utils.restTemplate; import org.springframework.http ...

  5. 「JSOI2011」任务调度

    「JSOI2011」任务调度 传送门 一开始还在想写平衡树,看到 \(\text{TRANS}\) 操作后就晓得要用可并堆了. 这题好像就是个可并堆的板子题??? ADD 直接往对应的对里面加元素 D ...

  6. 【网寻】IE F12 后报错,无法查看 DOM 等信息

    错误图片: 解决办法 : 安装Windows7补丁:KB3008923: 补丁下载地址: http://www.microsoft.com/en-us/download/details.aspx?id ...

  7. javascript对象创建及继承

    //****************************************************************************** //创建类的多种方式 //------ ...

  8. 02-03Android学习进度报告三

    今天主要学习了线性布局和相对布局的概念和区别,以及线性布局和相对布局的优缺点. 经过搜素发现,我们屏幕适配的使用用的比较多的就是LinearLayout的权重属性weight,我 学习了一些 Line ...

  9. java中如何修改事务的隔离级别

    事务的特性: 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生. (多条语句要么都成功,要么都失败.) 一致性(Consistency)事务前后 ...

  10. 说说maven依赖冲突,依赖调解,依赖传递和依赖范围

    说maven依赖冲突之前需要先说说maven的 依赖传递. 依赖传递 当前项目引入了一个依赖,该依赖的依赖也会被引入项目.更加准确的说法是,maven会解析直接依赖的POM,将那些必要的间接依赖,以传 ...