前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你不知道的 forEach(javascript)

你不知道的 forEach(javascript)

作者头像
奋飛
发布2021-12-30 21:01:55
3470
发布2021-12-30 21:01:55
举报
文章被收录于专栏:Super 前端Super 前端

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

代码语言:javascript
复制
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.

代码语言:javascript
复制
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.

代码语言:javascript
复制
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;

代码语言:javascript
复制
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.

代码语言:javascript
复制
ary = [1, 2]
ary.forEach(i => {
  console.log(`execute ${i}`)
  delete ary[1]
})

// 输出结果:
execute 1

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

终止执行

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

代码语言:javascript
复制
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 的时候,中止循环。

代码语言:javascript
复制
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

【重点】异步执行

模拟异步函数

代码语言:javascript
复制
function asyncFn (num) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(num), 1000*num)
  })
}

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

代码语言:javascript
复制
ary.forEach(async num => {
  let res = await asyncFn(num)
  console.log(res)
})
// 输出结果:1 2 3

ECMA262规范:

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
let iterators = ary[Symbol.iterator]()
iterators.next()	// {value: 3, done: false}

for...of 的实现

代码语言:javascript
复制
let iterators = ary[Symbol.iterator]()
let res = iterators.next()
while (!res.done) {
  let value = res.value
  await asyncFn(value)
  res = iterators.next()
}

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

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

实现斐波那契

代码语言:javascript
复制
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
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-09-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 跳过不存在的元素
  • callbackfn 中新增加的元素不会被处理
  • callbackfn 中变更元素
  • 终止执行
  • 【重点】异步执行
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档