精通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() 方法对数组的每个元素执行一次给定的函数。
-
const array1 = [‘a’, ‘b’, ‘c’];
-
array1.forEach(element => console.log(element));
-
// expected output: “a”
-
// expected output: “b”
-
// expected output: “c”
参数
callback
为数组中每个元素执行的函数,该函数接收一至三个参数:
-
currentValue 数组中正在处理的当前元素。
-
index 可选 数组中正在处理的当前元素的索引。
-
array 可选 forEach() 方法正在操作的数组。
thisArg 可选 可选参数。当执行回调函数 callback 时,用作 this 的值。
返回值
undefined。
array.forEach()描述
forEach() 方法按升序为数组中含有效值的每一项执行一次 callback函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上)。
可依次向 callback 函数传入三个参数:
-
数组当前项的值
-
数组当前项的索引
-
数组对象本身
如果 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 函数,或进行任何其他操作。
-
const arraySparse = [1,3,7];
-
let numCallbackRuns = 0;
-
arraySparse.forEach(function(element){
-
console.log(element);
-
numCallbackRuns++;
-
});
-
console.log("numCallbackRuns: ", numCallbackRuns);
-
// 1
-
// 3
-
// 7
-
// numCallbackRuns: 3
案例 02 将 for 循环转换为 forEach
-
const items = [‘item1’, ‘item2’, ‘item3’];
-
const copy = [];
-
// before
-
for (let i=0; i<items.length; i++) {
-
copy.push(items[i]);
-
}
-
// after
-
items.forEach(function(item){
-
copy.push(item);
-
});
案例 03 打印出数组的内容
注意:为了在控制台中显示数组的内容,你可以使用 console.table() 来展示经过格式化的数组。下面的例子则是另一种使用forEach() 的格式化的方法。
下面的代码会为每一个数组元素输出一行记录:
-
function logArrayElements(element, index, array) {
-
console.log('a[' + index + '] = ' + element);
-
}
-
// 注意索引 2 被跳过了,因为在数组的这个位置没有项
-
[2, 5, , 9].forEach(logArrayElements);
-
// logs:
-
// a[0] = 2
-
// a[1] = 5
-
// a[3] = 9
案例 04 使用 thisArg
举个勉强的例子,按照每个数组中的元素值,更新一个对象的属性:
-
function Counter() {
-
this.sum = 0;
-
this.count = 0;
-
}
-
Counter.prototype.add = function(array) {
-
array.forEach(function(entry) {
-
this.sum += entry;
-
++this.count;
-
}, this);
-
// ^---- Note
-
};
-
const obj = new Counter();
-
obj.add([2, 5, 9]);
-
obj.count;
-
// 3 === (1 + 1 + 1)
-
obj.sum;
-
// 16 === (2 + 5 + 9)
因为 thisArg 参数(this)传给了 forEach(),每次调用时,它都被传给 callback 函数,作为它的 this 值。
注意:如果使用箭头函数表达式来传入函数参数, thisArg 参数会被忽略,因为箭头函数在词法上绑定了 this 值。
案例 05 对象复制器函数
下面的代码会创建一个给定对象的副本。 创建对象的副本有不同的方法,以下是只是一种方法,并解释了 Array.prototype.forEach() 是如何使用 ECMAScript 5 Object.* 元属性(meta property)函数工作的。
-
function copy(obj) {
-
const copy = Object.create(Object.getPrototypeOf(obj));
-
const propNames = Object.getOwnPropertyNames(obj);
-
propNames.forEach(function(name) {
-
const desc = Object.getOwnPropertyDescriptor(obj, name);
-
Object.defineProperty(copy, name, desc);
-
});
-
return copy;
-
}
-
const obj1 = { a: 1, b: 2 };
-
const obj2 = copy(obj1); // 现在 obj2 看起来和 obj1 一模一样了
案例 06 如果数组在迭代时被修改了,则其他元素会被跳过。
下面的例子会输出 “one”, “two”, “four”。当到达包含值 “two” 的项时,整个数组的第一个项被移除了,这导致所有剩下的项上移一个位置。因为元素 “four” 正位于在数组更前的位置,所以"three" 会被跳过。 forEach() 不会在迭代之前创建数组的副本。
-
var words = [‘one’, ‘two’, ‘three’, ‘four’];
-
words.forEach(function(word) {
-
console.log(word);
-
if (word === 'two') {
-
words.shift();
-
}
-
});
-
// one
-
// two
-
// four
案例 07 扁平化数组
下面的示例仅用于学习目的。如果你想使用内置方法来扁平化数组,你可以考虑使用 Array.prototype.flat()(预计将成为 ES2019 的一部分,并且已在主要浏览器中实现)或参考其 polyfill。
-
/**
-
* Flattens passed array in one dimensional array
-
*
-
* @params {array} arr
-
* @returns {array}
-
*/
-
function flatten(arr) {
-
const result = [];
-
arr.forEach((i) => {
-
if (Array.isArray(i))
-
result.push(...flatten(i));
-
else
-
result.push(i);
-
})
-
return result;
-
}
-
// Usage
-
const problem = [1, 2, 3, [4, 5, [6, 7], 8, 9]];
-
flatten(problem); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
案例08 针对 promise 或 async 函数的使用备注
如果使用 promise 或 async函数作为 forEach() 等类似方法的 callback 参数,最好对造成的执行顺序影响多加考虑,否则容易出现错误。
-
let ratings = [5, 4, 5];
-
let sum = 0;
-
let sumFunction = async function (a, b) {
-
return a + b;
-
}
-
ratings.forEach(async function(rating) {
-
sum = await sumFunction(sum, rating);
-
})
-
console.log(sum);
-
// Expected output: 14
-
// Actual output: 0
文章来源:网络 版权归原作者所有
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系小编,我们将立即处理
相关文章:
精通Javascript 函数式array.forEach的8个案例
JavaScript是当今流行语言中对函数式编程支持最好的编程语言。我们继续构建函数式编程的基础,在前文中分解介绍了帮助我们组织思维的四种方法,分别为: array.reduce方法 帮你精通JS:神奇的array.reduce方法的10个案例 array.map方…...
忘记无线网络密码的几种解决办法
排名由简单到复杂 1网线直连; 2查看密码备份文件; 3问人要密码; 4已连接无线设备生成二维码扫描即可上网; 5路由器有wps功能,设备输入pin码可上网; 6已连接电脑右键wifi名,选择属性,…...
git add你真的用明白了吗?你还在无脑git add .?进入暂存区啥意思?
git add 命令用于将文件的改动添加到暂存区(staging area),为下一次提交做好准备。简单来说,它标记了哪些文件或改动会被纳入下次 git commit 中。以下是 git add 的作用和使用场景: 1. 作用 git add 将指定文件或文…...
Vue-Route
一、相关理解 1. vue-router的理解 vue的一个插件库,专门用来实现SPA应用 2. 对SPA应用的理解 单页Web应用整个应用只有一个完整的页面点击页面中的导航链接不会刷新页面,只会做页面的局部更新数据需要通过ajax请求获取 3. 路由的理解 什么是路由 …...

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

芯片上音频相关的验证
通常芯片设计公司(比如QUALCOMM)把芯片设计好后交由芯片制造商(比如台积电)去生产,俗称流片。芯片设计公司由ASIC部门负责设计芯片。ASIC设计的芯片只有经过充分的验证(这里说的验证是FPGA(现场…...

【C/C++】函数的递归
1.什么是递归? 递归就是递推和回归,以数学函数f(x) x为例: 递推:f(x) f(x - 1) 1 ; f(x - 1) f(x - 2) 1 ; f(x - 2) …… 回归:……; f(x - 2) f(x - 1) 1 ; f(x - 1) f(x) 1; 可以看出, 递推和…...

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

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

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

内容安全与系统构建加速,助力解决生成式AI时代的双重挑战
内容安全与系统构建加速,助力解决生成式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、源码解析 代码路径:scrapy/core/downloader/__init__.py 详细代码解析,请看代码注释 """Download handlers for different schemes"""import logging from typing import TYPE_CHECKING, Any, Callable, Dict, Gener…...
shell基础-awk
awk 是一个强大的文本处理工具,广泛用于 Unix 和 Linux 系统中。它可以用来处理和分析文本文件,特别是那些包含结构化数据的文件。以下是 awk 的基础知识和一些常用示例。 基本概念 记录和字段: 记录:awk 处理的每一行文本称为一…...
@Controller 和 @RestController 区别
功能范畴: Controller:用于定义一个控制器类,主要用于处理用户请求并返回视图(通常是HTML页面)。常常与 Spring MVC 的视图解析器一起使用。RestController:是一个特殊类型的控制器,用于返回数据而不是视图…...

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

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

Native Crash 信号速查
重点信号 SIGSEGV(11) signal segmentation violation:段错误无效内存访问访问无权访问的内存空指针、越界访问(mmap?) SIGBUS(7) Bus Error:总线错误非法内存访问访问 …...

【工具变量】自由贸易试验区试点DID数据集(2003-2023年)
数据简介:自由贸易试验区(Free Trade Zone,简称FTZ)是中国ZF在新形势下为了推进GG开放、提高开放型经济水平而采取的重要战略举措。自贸试验区在一国的部分领土内运入任何货物,被认为在关境以外,免于实施惯…...
js-在数组中根据name查找出对应id(find与filter方法)
1.根据name查找出对应id 使用数组的 find 方法来根据对象的某个属性(如名称)查找对应的对象,并获取该对象的 id 属性。 2.find 方法 const array [ { id: 1, name: Alice }, { id: 2, name: Bob }, { id: 3, name: Charlie } ]; 使用…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...