当前位置: 首页 > news >正文

精通Javascript 函数式array.forEach的8个案例

JavaScript是当今流行语言中对函数式编程支持最好的编程语言。我们继续构建函数式编程的基础,在前文中分解介绍了帮助我们组织思维的四种方法,分别为:

  • array.reduce方法 帮你精通JS:神奇的array.reduce方法的10个案例

  • array.map方法 帮你精通JS:神奇的array.map的6个案例

  • array.flat方法,以及array.flatMap帮你精通JS: array.flat与flatMap用法指南

以上四种方法的共同点都是对array作转换和变形,而且都不需要陷入到琐碎loop实现细节的 dirty details之中。

接下来,我们将学习更加通用的函数式迭代方法 array.forEach()。

一句话概括区分 forEach 与map 的区别,pure-function 就用 map,impure-function 则用 forEach。

array.forEach()语法概述
forEach() 方法对数组的每个元素执行一次给定的函数。

  1. const array1 = [‘a’, ‘b’, ‘c’];

  2. array1.forEach(element => console.log(element));

  3. // expected output: “a”

  4. // expected output: “b”

  5. // expected output: “c”

参数
callback

为数组中每个元素执行的函数,该函数接收一至三个参数:

  • currentValue 数组中正在处理的当前元素。

  • index 可选 数组中正在处理的当前元素的索引。

  • array 可选 forEach() 方法正在操作的数组。

thisArg 可选 可选参数。当执行回调函数 callback 时,用作 this 的值。

返回值

undefined。

array.forEach()描述
forEach() 方法按升序为数组中含有效值的每一项执行一次 callback函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上)。

可依次向 callback 函数传入三个参数:

  1. 数组当前项的值

  2. 数组当前项的索引

  3. 数组对象本身

如果 thisArg 参数有值,则每次callback 函数被调用时,this 都会指向thisArg 参数。如果省略了 thisArg 参数,或者其值为 null 或 undefined,this则指向全局对象。按照函数观察到 this 的常用规则,callback函数最终可观察到 this 值。

forEach() 遍历的范围在第一次调用 callback 前就会确定。调用 forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach() 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()),之后的元素将被跳过——参见下面的示例。

forEach() 为每个数组元素执行一次 callback 函数;与 map() 或者 reduce()不同的是,它总是返回 undefined 值,并且不可链式调用。其典型用例是在一个调用链的最后执行副作用(side effects,函数式编程上,指函数进行 返回结果值 以外的操作)。

forEach() 被调用时,不会改变原数组,也就是调用它的数组(尽管 callback 函数在被调用时可能会改变原数组)。(此处说法可能不够明确,具体可参考EMCA语言规范:‘forEach does not directly mutate the object on which it is called but the object may be mutated by the calls to callback function.’,即 forEach 不会直接改变调用它的对象,但是那个对象可能会被 callback 函数改变。)

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

若你需要提前终止循环,你可以使用:

· 一个简单的 for 循环

· for…of / for…in 循环

· Array.prototype.every()

· Array.prototype.some()

· Array.prototype.find()

· Array.prototype.findIndex()

这些数组方法则可以对数组元素判断,以便确定是否需要继续遍历:

· every()

· some()

· find()

· findIndex()

只要条件允许,也可以使用 filter() 提前过滤出需要遍历的部分,再用 forEach() 处理。

案例 01 不对未初始化的值进行任何操作(稀疏数组)
如你所见,3 和 7 之间空缺的数组单元未被 forEach() 调用 callback 函数,或进行任何其他操作。

  1. const arraySparse = [1,3,7];

  2. let numCallbackRuns = 0;

  3. arraySparse.forEach(function(element){

  4.  console.log(element); 
    
  5.  numCallbackRuns++; 
    
  6. });

  7. console.log("numCallbackRuns: ", numCallbackRuns);

  8. // 1

  9. // 3

  10. // 7

  11. // numCallbackRuns: 3

案例 02 将 for 循环转换为 forEach

  1. const items = [‘item1’, ‘item2’, ‘item3’];

  2. const copy = [];

  3. // before

  4. for (let i=0; i<items.length; i++) {

  5.  copy.push(items[i]); 
    
  6. }

  7. // after

  8. items.forEach(function(item){

  9. copy.push(item);

  10. });

案例 03 打印出数组的内容
注意:为了在控制台中显示数组的内容,你可以使用 console.table() 来展示经过格式化的数组。下面的例子则是另一种使用forEach() 的格式化的方法。

下面的代码会为每一个数组元素输出一行记录:

  1. function logArrayElements(element, index, array) {

  2.  console.log('a[' + index + '] = ' + element); 
    
  3. }

  4. // 注意索引 2 被跳过了,因为在数组的这个位置没有项

  5. [2, 5, , 9].forEach(logArrayElements);

  6. // logs:

  7. // a[0] = 2

  8. // a[1] = 5

  9. // a[3] = 9

案例 04 使用 thisArg
举个勉强的例子,按照每个数组中的元素值,更新一个对象的属性:

  1. function Counter() {

  2.  this.sum = 0; 
    
  3.  this.count = 0; 
    
  4. }

  5. Counter.prototype.add = function(array) {

  6.  array.forEach(function(entry) { 
    
  7.    this.sum += entry; 
    
  8.    ++this.count; 
    
  9.  }, this); 
    
  10. // ^---- Note

  11. };

  12. const obj = new Counter();

  13. obj.add([2, 5, 9]);

  14. obj.count;

  15. // 3 === (1 + 1 + 1)

  16. obj.sum;

  17. // 16 === (2 + 5 + 9)

因为 thisArg 参数(this)传给了 forEach(),每次调用时,它都被传给 callback 函数,作为它的 this 值。

注意:如果使用箭头函数表达式来传入函数参数, thisArg 参数会被忽略,因为箭头函数在词法上绑定了 this 值。

案例 05 对象复制器函数
下面的代码会创建一个给定对象的副本。 创建对象的副本有不同的方法,以下是只是一种方法,并解释了 Array.prototype.forEach() 是如何使用 ECMAScript 5 Object.* 元属性(meta property)函数工作的。

  1. function copy(obj) {

  2.  const copy = Object.create(Object.getPrototypeOf(obj)); 
    
  3.  const propNames = Object.getOwnPropertyNames(obj); 
    
  4.  propNames.forEach(function(name) { 
    
  5.    const desc = Object.getOwnPropertyDescriptor(obj, name); 
    
  6.    Object.defineProperty(copy, name, desc); 
    
  7.  }); 
    
  8. return copy;

  9. }

  10. const obj1 = { a: 1, b: 2 };

  11. const obj2 = copy(obj1); // 现在 obj2 看起来和 obj1 一模一样了

案例 06 如果数组在迭代时被修改了,则其他元素会被跳过。
下面的例子会输出 “one”, “two”, “four”。当到达包含值 “two” 的项时,整个数组的第一个项被移除了,这导致所有剩下的项上移一个位置。因为元素 “four” 正位于在数组更前的位置,所以"three" 会被跳过。 forEach() 不会在迭代之前创建数组的副本。

  1. var words = [‘one’, ‘two’, ‘three’, ‘four’];

  2. words.forEach(function(word) {

  3.  console.log(word); 
    
  4.  if (word === 'two') { 
    
  5.    words.shift(); 
    
  6.  } 
    
  7. });

  8. // one

  9. // two

  10. // four

案例 07 扁平化数组
下面的示例仅用于学习目的。如果你想使用内置方法来扁平化数组,你可以考虑使用 Array.prototype.flat()(预计将成为 ES2019 的一部分,并且已在主要浏览器中实现)或参考其 polyfill。

  1. /**

  2. * Flattens passed array in one dimensional array 
    
  3. * 
    
  4. * @params {array} arr 
    
  5. * @returns {array} 
    
  6. */ 
    
  7. function flatten(arr) {

  8.  const result = []; 
    
  9. arr.forEach((i) => {

  10. if (Array.isArray(i)) 
    
  11.   result.push(...flatten(i)); 
    
  12. else 
    
  13.   result.push(i); 
    
  14. })

  15. return result;

  16. }

  17. // Usage

  18. const problem = [1, 2, 3, [4, 5, [6, 7], 8, 9]];

  19. flatten(problem); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

案例08 针对 promise 或 async 函数的使用备注
如果使用 promise 或 async函数作为 forEach() 等类似方法的 callback 参数,最好对造成的执行顺序影响多加考虑,否则容易出现错误。

  1. let ratings = [5, 4, 5];

  2. let sum = 0;

  3. let sumFunction = async function (a, b) {

  4.    return a + b; 
    
  5. }

  6. ratings.forEach(async function(rating) {

  7. sum = await sumFunction(sum, rating); 
    
  8. })

  9. console.log(sum);

  10. // Expected output: 14

  11. // Actual output: 0

文章来源:网络 版权归原作者所有

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系小编,我们将立即处理

相关文章:

精通Javascript 函数式array.forEach的8个案例

JavaScript是当今流行语言中对函数式编程支持最好的编程语言。我们继续构建函数式编程的基础&#xff0c;在前文中分解介绍了帮助我们组织思维的四种方法&#xff0c;分别为&#xff1a; array.reduce方法 帮你精通JS&#xff1a;神奇的array.reduce方法的10个案例 array.map方…...

忘记无线网络密码的几种解决办法

排名由简单到复杂 1网线直连&#xff1b; 2查看密码备份文件&#xff1b; 3问人要密码&#xff1b; 4已连接无线设备生成二维码扫描即可上网&#xff1b; 5路由器有wps功能&#xff0c;设备输入pin码可上网&#xff1b; 6已连接电脑右键wifi名&#xff0c;选择属性&#xff0c;…...

git add你真的用明白了吗?你还在无脑git add .?进入暂存区啥意思?

git add 命令用于将文件的改动添加到暂存区&#xff08;staging area&#xff09;&#xff0c;为下一次提交做好准备。简单来说&#xff0c;它标记了哪些文件或改动会被纳入下次 git commit 中。以下是 git add 的作用和使用场景&#xff1a; 1. 作用 git add 将指定文件或文…...

Vue-Route

一、相关理解 1. vue-router的理解 vue的一个插件库&#xff0c;专门用来实现SPA应用 2. 对SPA应用的理解 单页Web应用整个应用只有一个完整的页面点击页面中的导航链接不会刷新页面&#xff0c;只会做页面的局部更新数据需要通过ajax请求获取 3. 路由的理解 什么是路由 …...

字符串逆序(c语言)

错误代码 #include<stdio.h>//字符串逆序 void reverse(char arr[], int n) {int j 0;//采用中间值法//访问数组中第一个元素和最后一个元素//交换他们的值&#xff0c;从而完成了字符串逆序//所以这个需要临时变量for (j 0; j < n / 2; j){char temp arr[j];arr[…...

芯片上音频相关的验证

通常芯片设计公司&#xff08;比如QUALCOMM&#xff09;把芯片设计好后交由芯片制造商&#xff08;比如台积电&#xff09;去生产&#xff0c;俗称流片。芯片设计公司由ASIC部门负责设计芯片。ASIC设计的芯片只有经过充分的验证&#xff08;这里说的验证是FPGA&#xff08;现场…...

【C/C++】函数的递归

1.什么是递归&#xff1f; 递归就是递推和回归&#xff0c;以数学函数f(x) x为例&#xff1a; 递推&#xff1a;f(x) f(x - 1) 1 ; f(x - 1) f(x - 2) 1 ; f(x - 2) …… 回归&#xff1a;……; f(x - 2) f(x - 1) 1 ; f(x - 1) f(x) 1; 可以看出&#xff0c; 递推和…...

《链表篇》---两两交换链表中的节点(中等)

题目传送门 1.定义一个虚拟节点链接链表 2.定义一个当前节点指向虚拟节点 3.在当前节点的下一个节点和下下一个节点都不为null的情况下。 定义 node1和node2。保存当前节点后面两个节点的地址。cur.next node2;node1.next node2.next;node2.next node1;cur node1; 4.返回re…...

Fakelocation 步道乐跑(Root真机篇)

前言:需要 Fakelocation&#xff0c;真机Root,步道乐跑&#xff0c;Dia&#xff0c;MT管理器系统需求 Fakelocation | MT管理器 | Dia | 环境模块 任务一 真机Root&#xff08;德尔塔&#xff0c;过momo&#xff0c;刷环境模块&#xff09; 任务二 前往Dia查看包名&#xff08…...

PyEcharts | 全局配置项中初始配置项和区域缩放配置项的使用

全局配置项可通过set_global_opts方法设置 一个图像主要的内容 引入包 from pyecharts.charts import Bar,Line from pyecharts import options as opts from pyecharts.faker import Faker from pyecharts.globals import ThemeType,RenderTypefrom pyecharts.globals imp…...

突破语言壁垒:Cohere 发布多语言大模型 Aya Expanse

前沿科技速递&#x1f680; 在多语言大模型领域&#xff0c;Cohere 再次迎来了突破&#xff01;10月24日&#xff0c;Cohere的研究实验室 Cohere For AI 正式发布了最新的多语言AI模型家族 —— Aya Expanse。该系列模型开放了8B和32B参数两个版本,为全球AI爱好者带来了崭新的多…...

内容安全与系统构建加速,助力解决生成式AI时代的双重挑战

内容安全与系统构建加速&#xff0c;助力解决生成式AI时代的双重挑战 0. 前言1. PRCV 20241.1 大会简介1.2 生成式 Al 时代的内容安全与系统构建加速 2. 生成式 AI2.1 生成模型2.2 生成模型与判别模型的区别2.3 生成模型的发展 3. GAI 内容安全3.1 GAI 时代内容安全挑战3.2 图像…...

Scrapy源码解析:DownloadHandlers设计与解析

1、源码解析 代码路径&#xff1a;scrapy/core/downloader/__init__.py 详细代码解析&#xff0c;请看代码注释 """Download handlers for different schemes"""import logging from typing import TYPE_CHECKING, Any, Callable, Dict, Gener…...

shell基础-awk

awk 是一个强大的文本处理工具&#xff0c;广泛用于 Unix 和 Linux 系统中。它可以用来处理和分析文本文件&#xff0c;特别是那些包含结构化数据的文件。以下是 awk 的基础知识和一些常用示例。 基本概念 记录和字段&#xff1a; 记录&#xff1a;awk 处理的每一行文本称为一…...

@Controller 和 @RestController 区别

功能范畴: Controller&#xff1a;用于定义一个控制器类&#xff0c;主要用于处理用户请求并返回视图&#xff08;通常是HTML页面&#xff09;。常常与 Spring MVC 的视图解析器一起使用。RestController&#xff1a;是一个特殊类型的控制器&#xff0c;用于返回数据而不是视图…...

【数据库设计】规范设计理论之数据依赖的公理系统(1)

知道范式的几种分类之后还并不能帮助我们设计一款好的数据库&#xff0c;在对关系进行拆解&#xff08;指模式分解&#xff09;之前&#xff0c;我们需要引入一个理论基础让设计过程变得有迹可循和具备一定的严谨性以此来支撑数据库背后的可靠性。 Armstrong公理系统 所谓公理…...

Leetcode 合并两个数组

算法思想是双指针从后往前合并&#xff0c;利用了 nums1 数组的尾部空间来存储合并后的结果&#xff0c;从而避免了额外空间的使用。具体步骤如下&#xff1a; 初始化指针&#xff1a; i 指向 nums1 的有效元素末尾&#xff0c;即位置 m - 1。j 指向 nums2 的末尾&#xff0c;即…...

Native Crash 信号速查

重点信号 SIGSEGV&#xff08;11&#xff09; signal segmentation violation&#xff1a;段错误无效内存访问访问无权访问的内存空指针、越界访问&#xff08;mmap&#xff1f;&#xff09; SIGBUS&#xff08;7&#xff09; Bus Error&#xff1a;总线错误非法内存访问访问 …...

【工具变量】自由贸易试验区试点DID数据集(2003-2023年)

数据简介&#xff1a;自由贸易试验区&#xff08;Free Trade Zone&#xff0c;简称FTZ&#xff09;是中国ZF在新形势下为了推进GG开放、提高开放型经济水平而采取的重要战略举措。自贸试验区在一国的部分领土内运入任何货物&#xff0c;被认为在关境以外&#xff0c;免于实施惯…...

js-在数组中根据name查找出对应id(find与filter方法)

1.根据name查找出对应id 使用数组的 find 方法来根据对象的某个属性&#xff08;如名称&#xff09;查找对应的对象&#xff0c;并获取该对象的 id 属性。 2.find 方法 const array [ { id: 1, name: Alice }, { id: 2, name: Bob }, { id: 3, name: Charlie } ]; 使用…...

推荐:自然语言处理方向的一些创新点

以下是自然语言处理研究方向的一些创新点&#xff1a; 一、预训练模型的改进与优化 模型架构创新 融合多模态信息&#xff1a; 传统的自然语言处理模型主要处理文本信息。创新点在于将图像、音频等多模态信息融合到预训练模型中。例如&#xff0c;对于描述一幅画的文本&#x…...

成都睿明智科技有限公司抖音电商服务的领航者

在这个短视频风起云涌的时代&#xff0c;抖音电商以其独特的魅力迅速崛起&#xff0c;成为无数商家争夺流量与销量的新战场。在这片红海之中&#xff0c;如何脱颖而出&#xff0c;实现销售额的飞跃&#xff1f;今天&#xff0c;就让我们一同走进成都睿明智科技有限公司&#xf…...

【大数据学习 | kafka】kafka的整体框架与数据结构

1. kafka的整体框架 首先kafka启动以后所有的broker都会向zookeeper进行注册&#xff0c;在/brokers/ids中以列表的形式展示所有的节点&#xff0c;在/controller节点中使用独享锁实现broker的选举&#xff0c;其中一个机器为主节点。其他的为从节点&#xff0c;选举的根本原则…...

隐私保护下的数据提取策略

在隐私保护下进行数据提取&#xff0c;需要采取一系列策略来确保个人隐私得到妥善保护&#xff0c;同时满足数据使用的需求。以下是一些关键的策略和方法&#xff1a; 一、数据最小化原则 定义&#xff1a;仅收集和提取必要的数据&#xff0c;避免收集过多的个人信息或不相关…...

vue 和 django 报 CORS(跨域资源共享,Cross-Origin Resource Sharing)是一种跨域访问的机制,

在使用 Vue 和 Django 进行前后端分离开发时&#xff0c;如果遇到 AxiosError: Network Error 的错误&#xff0c;通常可能是由于以下几种原因引起的。下面列出了一些常见的原因和解决方案。 1. CORS&#xff08;跨源资源共享&#xff09;问题 当你的 Vue 应用和 Django 后端…...

「Mac畅玩鸿蒙与硬件3」鸿蒙开发环境配置篇3 - DevEco Studio 插件安装与配置

本篇将专注于如何在 DevEco Studio 中安装和配置必要的插件&#xff0c;以增强开发功能和提升效率。通过正确配置插件&#xff0c;开发流程能够得到简化&#xff0c;开发体验也会更加顺畅。 关键词 插件安装配置优化DevEco Studio开发工具 一、插件的重要性 插件可以大幅扩展…...

【论文阅读】PGAN

1. WHY 问题 图像超分辨率一直是一个热门研究课题&#xff0c;具有重要的应用价值。基于生成对抗网络GAN的单幅图像超分辨率方法显示重建图像与人类视觉特征更一致。因此&#xff0c;基于 GAN 的网络优化已成为图像超分辨率的主流。然而&#xff0c;一些最新研究表明&#xf…...

基于Unet卷积神经网络的脑肿瘤MRI分割

项目源码获取方式见文章末尾&#xff01; 回复暗号&#xff1a;13&#xff0c;免费获取600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【YOLO模型实现农作物病虫害虫识别带GUI界面】 2.【卫星图像道路检测DeepLabV3P…...

[java][基础]HTTPTomcatServlet

1&#xff0c;Web概述 1.1 Web和JavaWeb的概念 Web是全球广域网&#xff0c;也称为万维网(www)&#xff0c;能够通过浏览器访问的网站。 在我们日常的生活中&#xff0c;经常会使用浏览器去访问百度、京东、传智官网等这些网站&#xff0c;这些网站统称为Web网站。如下就是通…...

【开源免费】基于SpringBoot+Vue.JS网上超市系统(JAVA毕业设计)

本文项目编号 T 037 &#xff0c;文末自助获取源码 \color{red}{T037&#xff0c;文末自助获取源码} T037&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…...