前言

本文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. node vue 项目git 管理

    push 上传到云的时候,依赖包及相关文件是不上传上去的, 所以每次克隆到本地后,node 项目运行前须要 npm install 安装对应依赖 vue 项目编译前也须要  npm install,安 ...

  2. ANSYS 非线性材料模型简介1 ---常用弹塑性模型

    目录 1. 材料非线性 2. 三个准则 2.1 屈服准则 2.2 流动准则 2.3 强化准则 3. 常用弹塑性模型 3.1 双线性等向强化 3.2 多线性等向强化 3.3 非线性等向强化 3.4 双线 ...

  3. Http 状态码总结

    HTTP 状态码列表 一. 1 开头 (继续执行) 服务器收到请求,需要请求者继续执行操作 100:(continue) 客户端继续请求 101:(Switching Protocols) 切换协议, ...

  4. Yar并行的RPC框架的简单使用

    前言: RPC,就是Remote Procedure Call的简称呀,翻译成中文就是远程过程调用 RPC要解决的两个问题: 解决分布式系统中,服务之间的调用问题. 远程调用时,要能够像本地调用一样方 ...

  5. 获取 AppStore 中 应用 的 IPA 包文件(Mac OS 13+)

    在 Mac OS 12.7 之前,可以通过 iTunes 直接下载 App Store 中应用的 IPA 包,可以提取其他应用的资源图片,查看信息等操作.之后 苹果 公司禁用了这一功能,不能直接通过 ...

  6. 在Linux CentOS 下安装JDK 1.8

    一首先去官网下载linux 版本JDK1.8  http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21331 ...

  7. HackInOS靶机渗透

    一.环境配置 攻击机kali搭建在Vmware,桥接模式,ip:192.168.43.48 靶机HackInOS需要用VirtualBox导入ova文件,桥接模式,启动完成之后, 选择Ubuntu系统 ...

  8. [IDEA] Idea复制文件到项目一直updating indices的问题

    通常我们在开发JavaWeb项目的时候,都需要先将网页写好,在进行复制到web目录下,如果里面包含了很多的资源文件,就会造成一直updating indices. 方法一: 这是因为项目需要对web目 ...

  9. springboot集成拦截器

    一.首先对HandlerInterceptor进行封装,封装为MappingInterceptor.封装的方法里添加拦截器起作用的路径addPathPatterns(),及需要排除路径的方法exclu ...

  10. 「CQOI2009」中位数

    「CQOI2009」中位数 传送门 这道题将会用到一点桶的思想. 首先我们可以在排列中先找到 \(b\) 的位置(找不到的话就直接输出 \(0\)). 然后我们从 \(b\) 的位置(设为 \(p\) ...