你不知道的foreach(javascript)(代码片段)

奋飛 奋飛     2023-01-06     596

关键词:

Thinking系列,旨在利用10分钟的时间传达一种可落地的编程思想或解决方案。

Array.prototype.forEach ( callbackfn [ , thisArg ] )

规范地址(下述引用文,均源自该规范):https://tc39.es/ecma262/#sec-array.prototype.foreach

跳过不存在的元素

callbackfn 只对数组中实际存在的元素调用;数组中缺少元素时不调用该函数。

forEach calls callbackfn once for each element present in the array, in ascending order. callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array.

let ary = [3, undefined, 2, , 1]
console.log(ary.length)	// 5
ary.forEach(i => 
  console.log(`execute $i`)
)

// 输出结果:
execute 3
execute undefined
execute 2
execute 1

元素值为 undefinedcallbackfn 正常执行;元素值缺失callbackfn 直接跳过。

callbackfn 中新增加的元素不会被处理

在 forEach 调用开始后,追加到数组中的元素将不会被 callbackfn 访问。

Elements which are appended to the array after the call to forEach begins will not be visited by callbackfn.

ary = [1, 2]
ary.forEach(i => 
  console.log(`execute $i`)
  ary.push(ary.length)
)
console.log(ary.length)	// 4

// 输出结果:
execute 1
execute 2

执行了2次,但 ary 最终变成了 [1, 2, 2, 3]

callbackfn 中变更元素

① 如果数组中已有的元素被改变了,它们传递给 callbackfn 的值将是 forEach 访问它们时的值。

If existing elements of the array are changed, their value as passed to callbackfn will be the value at the time forEach visits them;

ary = [1, 2]
ary.forEach(i => 
  console.log(`execute $i`)
  ary[1] = 3
)

// 输出结果:
execute 1
execute 3

执行输出结果为 1 3callbackfn 获取的值为实时访问的值(修改后的值)。

② 在开始调用 forEach 之后和访问之前被删除的元素不会被访问。

elements that are deleted after the call to forEach begins and before being visited are not visited.

ary = [1, 2]
ary.forEach(i => 
  console.log(`execute $i`)
  delete ary[1]
)

// 输出结果:
execute 1

执行输出结果为 1callbackfn 中删除的元素不再被访问。

终止执行

forEach 中用 return 不会返回,函数会继续执行。

ary = [1, 2];
ary.forEach(i => 
  console.log(`execute $i`)
  return;//无效
)

// 输出结果:
execute 1
execute 2

return 并不会停止执行后续的操作。

原因: 仔细查看就会发现,return 结束的是当前 callbackfn ,并不是 forEach 函数本身。

解决方案:

① 使用 try 监视代码块,在需要中断的地方抛出异常;

② 官方推荐方法(替换方法),用 everysome 替代 forEach函数 – every 在碰到 return false 的时候,中止循环;some在碰到 return true 的时候,中止循环。

ary = [1, 2];
try 
  ary.forEach(i => 
    if (i === 2) throw new Error('终止执行')
    console.log(`execute $i`)
  )
 catch (e) 
// or
ary.every(i => 
  if (i === 2) return false
   console.log(`execute $i`)
)

// 输出结果:
execute 1

【重点】异步执行

模拟异步函数

function asyncFn (num) 
  return new Promise((resolve, reject) => 
    setTimeout(() => resolve(num), 1000*num)
  )

存在数组 const ary = [3, 2, 1] ,期望按照顺序输出 3 2 1

ary.forEach(async num => 
  let res = await asyncFn(num)
  console.log(res)
)
// 输出结果:1 2 3

ECMA262规范:

for (let k = 0, len = ary.length; k < len; k++) 
  if (k in ary) 
    let ele = ary[k]
    asyncFn(k)	// callbackfn(ele, k, ary)
  

callbackfn 的执行无法保证顺序(异步),所以会导致上述问题。

解决方案: 使用 for...of

for(let num of ary) 
  let res = await asyncFn(num)
  console.log(res)

// 输出结果:3 2 1

for...of 并不是简单的遍历执行,而是通过迭代器去遍历 Array.prototype[Symbol.iterator]()

规范地址:https://tc39.es/ecma262/#sec-for-in-and-for-of-statements

let iterators = ary[Symbol.iterator]()
iterators.next()	// value: 3, done: false

for...of 的实现

let iterators = ary[Symbol.iterator]()
let res = iterators.next()
while (!res.done) 
  let value = res.value
  await asyncFn(value)
  res = iterators.next()

执行完成当前值,才会调用下一个 next

再延伸一下,生成器 yield 也是迭代器

实现斐波那契

function* fibonacci()
  let [prev, cur] = [0, 1]
  while (true) 
    [prev, cur] = [cur, prev + cur]
    yield cur
  


for (let i of fibonacci()) 
  if (i > 50) break
  console.log(i)

  • https://juejin.cn/post/6844903986479251464#heading-5
  • https://juejin.cn/post/6844904004007247880#heading-70

记录--你不知道的foreach函数(代码片段)

...000*x))test()我们期望的结果是:321end但是实际上会输出:end123JavaScript中的forEach()方法是一个同步方法,它不支持处理异步函数。如果你在forEach中执行了异步函数,forEach()无法等待异步函数完成,它会继续执行下一项。这意味着如果... 查看详情

「译」foreach循环中你不知道的3件事(代码片段)

前言本文925字,阅读大约需要7分钟。总括:forEach循环中你不知道的3件事。原文地址:3thingsyoudidn’tknowabouttheforEachloopinJS公众号:「前端进阶学习」,回复「666」,获取一揽子前端技术书籍自弃者扶不起,自强者击不倒。正文你... 查看详情

《你不知道的javascript》系列分享专栏

《你不知道的JavaScript》系列分享专栏你不知道的JavaScript”系列就是要让不求甚解的JavaScript开发者迎难而上,深入语言内部,弄清楚JavaScript每一个零部件的用途《你不知道的JavaScript》已整理成PDF文档,点击可直接下载至本地查... 查看详情

每个javascript程序员都需要知道的5个数组方法

Array.forEach().forEach() 方法能够方便的让你 遍历数组里的每个元素,你可以在回调函数里对每个元素进行操作。.forEach()方法没有返回值,你不需要在回调函数里写return,这是无意义的。varanimals=[‘dog‘,‘cat‘,‘mouse‘];anim... 查看详情

《你不知道的javascript[中卷]》14——asynquence附录

 《你不知道的JavaScript[中卷]》【14】——asynquence附录 查看详情

你不知道的javascript(中卷)笔记

<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>你不知道的javascript(中卷)</title></head><body><scripttype="text/javascript">/*//封装对象包装vara=newBool 查看详情

javascript你不知道的事儿

if(in)语句letnames=['Lily','Barry','Dendi','Boogie','Lily'];letnameNum=names.reduce((pre,cur)=>{if(curinpre){//pre中是否有cur属性pre[cur]++;}else{pre[cur]=1;//为pre这个对象添加cur属性,并且赋值为1}returnpre;},{ 查看详情

你不知道的javascript之类型

JavaScript是一门简单易用的语言,应用广泛,同时它的语言机制又十分复杂和微妙,即使经验丰富的开发人员也需要用心学习才能真正掌握。《你不知道的JavaScript》中是这样定义类型的:类型是值的内部特征,它定义了值的行为... 查看详情

你不知道的javascript(上卷卷)笔记

<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>你不知道的javascript(上卷)</title></head><body></body></html>   查看详情

《你不知道的javascript》原型

1[[Prototype]][[Prototype]]是对其他对象的引用,几乎所有对象在创建时[[Prototype]]属性会被赋予非空值。varmyObject={a:2}myObject.a;//2 引用对象属性时会触发[[Get]]操作,它会检查对象本身是否有这个属性,如果有就使用它,但a不在myObj... 查看详情

《你不知道的javascript》——原型

                        查看详情

你不知道的javascript:有趣的settimeout

你不知道的Javascript:有趣的setTimeout有时候,小小的细节往往隐藏着大大的智慧今天在回顾JavaScript进阶用法的时候,发现一个有趣的问题,话不多说,先上代码:for(varj=0;j<10;j++){setTimeout(function(){console.log(j)},5000)}看到这三行代... 查看详情

《你不知道的javascript》整理——this

最近在读一本进阶的JavaScript的书《你不知道的JavaScript(上卷)》,这次研究了一下“this”。当一个函数被调用时,会创建一个活动记录(执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、... 查看详情

《你不知道的javascript》——this和对象原型

 《你不知道的javascript》【3】——this和对象原型https://www.bilibili.com/video/BV1iE411P7UP 浅显的总结《你不知道的js》this指向          右查找的副作用:查找到顶层都找不到,就会抛出 查看详情

你不知道的javascript笔记

类型:JavaScript有7种内置类型空值(null)未定义(undefined)布尔值(boolean)数字(number)字符串(string)对象(object)符号(symbol)   除对象以外,其他统称为“基本类型” 用typeof运算符来查看值的类型typeofundefined ==="undefi... 查看详情

《你不知道的javascript》整理——作用域提升与闭包

最近在读一本进阶的JavaScript的书《你不知道的JavaScript(上卷)》,里面分析了很多基础性的概念。可以更全面深入的理解JavaScript深层面的知识点。 一、函数作用域1)函数作用域就是作用域在一个“Function”里,属于... 查看详情

《你不知道的javascript》整理——对象

...造形式varmyObj=newObject();myObj.key=value; 二、类型对象是JavaScript的基础。1)基本类型在JavaScript中一共有六种主要类型(术语是“语言类型”):string、number、boolean、null、unde 查看详情

《你不知道的javascript》——闭包(代码片段)

第一部分还有最后的闭包没有讲...:1.非常浅显的阅读《你不知道的JavaScript》第一部分作用域与闭包https://www.bilibili.com/video/BV1jE411j7PU 从22分钟开始讲闭包              &nb 查看详情