前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ECMAScript 的 Iterator Helper 提案正式获得浏览器支持!

ECMAScript 的 Iterator Helper 提案正式获得浏览器支持!

作者头像
ConardLi
发布2024-04-15 16:33:42
1590
发布2024-04-15 16:33:42
举报
文章被收录于专栏:code秘密花园

大家好,我是 ConardLi

相信 Iterator(迭代器)这个概念大家并不陌生了,它和数组的概念类似,在 JavaScript 中都是用于存储和管理数据集合的机制。

但实际开发中,我们使用数组的场景要远远多于 Iterator ,主要原因还是因为 Iterator 太难用了,它不像数组一样给我们提供了很多便捷的高阶函数(如 map、filter 等) 。

Iterator helpers 提案正式出来解决这个问题的,它已经有几年时间了,目前处于 Stage3 阶段。

Iterator helpers 提供了一整套方法,使得迭代器的操作变得像数组一样简单。它允许你可以以链式调用的方式来组合方法,比如可以先用 .map() 处理数据,紧接着用 .filter() 筛选出需要的部分,最后用 .toArray() 将其转换成数组。

最近在 V8 12.2/Chrome 122 中,Iterator helpers 已经正式获得了支持。

在开始介绍之前,我们先看看 Iterator 和数组的区别,再实际开发中,我们在什么场景下更适合使用 Iterator

Iterator 和数组的对比

  1. 计算模式:
    • 数组是静态的: 数组在创建时就包含了一个固定大小的数据集合。你可以立即访问数组的任何元素,因为它们都是预先存储在内存中的。
    • 迭代器是惰性的(Lazy): Iterator 不必一开始就拥有所有的数据。它每次调用 next() 方法时才计算出下一个值。这意味着它可以表示无限的数据序列,并且可以按需产生数据,而不需要一开始就将所有数据加载到内存中。
  2. 性能和内存占用:
    • 数组可能占用更多内存: 因为需要预先存储所有元素。
    • 迭代器更高效: 它们可以在不占用大量内存的情况下,遍历巨大的甚至是无限的数据集。
  3. 使用场景的不同:
    • 数组用于存储元素集: 当你需要随机访问、多次遍历或者需要大量的数据操作时,使用数组是比较好的选择。
    • 迭代器用于遍历元素: 当数据集不需要一次性全部存储在内存中,或者希望按需计算每个值时,迭代器更为合适。

那么为啥有了使有了数组,我们还要还要用到 Iterator 呢?

  • 对于巨大或不确定大小的数据集, 迭代器可以有效地按需处理数据。例如,在处理文件流或网络请求等情况时,使用迭代器可以在数据到达时逐步处理,而不必等待所有数据都准备好。
  • 基于顺序的操作和管道(Pipelines): 当数据需要一系列的操作来转换时,迭代器使得这些转换可以按顺序进行,这类似于函数式编程中的管道机制。

实际开发中,下面这些可能会是使用到 Iterator 的例子:

  • 处理大型数据集: 当你需要处理大量数据时,比如从数据库读取数百万条记录,使用迭代器可以避免一次性将所有数据加载到内存中。
  • 与生成器配合进行复杂计算: 生成器提供了一种方便编写迭代逻辑的方法,当计算每个值代价昂贵或需要保持状态时,它们非常有用。
  • 异步操作: 在处理异步数据流,如读取网络资源时,异步迭代器使得按顺序处理异步事件成为可能。
  • 前端框架和库: 许多现代前端框架和库利用迭代器来处理或渲染列表和组件,提供更高效的数据更新和渲染策略。

聊完了 Iterator 和数组的区别,我们下面来看看 Iterator helpers 都提供了哪些方法?

.map(mapperFn)

类似数组的 map 方法,map 方法接受一个映射函数作为参数,在函数中我们可以对原本的参数进行处理,最中返回一个新的迭代器:

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 获取文章列表,返回他们的文本内容(标题)列表并且输出。
for (const post of posts.values().map((x) => x.textContent)) {
  console.log(post);
}

.filter(filtererFn)

类似数组的 filter 方法,filter 方法接受一个过滤器函数作为参数,根据我们自定义的逻辑过滤掉一些不需要的元素,然后返回一个新的迭代器。

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 过滤出包含 `ConardLi` 的博客文章的文本内容(标题),并在控制台输出它们。
for (const post of posts.values().filter((x) => x.textContent.includes('ConardLi'))) {
  console.log(post);
}

.take(limit)

take 方法接受一个整数作为参数,返回一个迭代器中前几个参数组成的新的迭代器。

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 选择最近的 17 篇博客文章,并在控制台输出它们。
for (const post of posts.values().take(17)) {
  console.log(post);
}

.drop(limit)

drop 方法接受一个整数作为参数,返回从原始迭代器中排除前 n 个元素后的新的的迭代器。

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 排除最近的 17 篇博客文章,打印新的迭代器
for (const post of posts.values().drop(17)) {
  console.log(post);
}

.flatMap(mapperFn)

flatMap() 方法可以看作是 map()flat() 的结合体。

首先,map() 方法会遍历迭代器的每个元素,并将元素通过一个函数进行处理,最后返回一个新的迭代器。然后,flat() 方法可以用来展平迭代器,也就迭代器迭代器的维度。将二维迭代器变为一维迭代器迭代器。

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 获取每篇博客文章的标签列表,并且拍平后返回
for (const tag of posts.values().flatMap((x) => x.querySelectorAll('.tag').values())) {
    console.log(tag.textContent);
}

.reduce(reducer [, initialValue ])

reduce 方法接受一个 reducer 函数以及一个可选的初始值作为参数。

"reducer" 函数有两个参数:累积器和当前值。在每次迭代中,累积器的值是上一次调用 "reducer" 函数的结果,当前值则是数组中正在处理的元素。

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 获取所有文章的标签列表。
const tagLists = posts.values().flatMap((x) => x.querySelectorAll('.tag').values());

// 获取列表中每个标签的文本内容。
const tags = tagLists.map((x) => x.textContent);

// 统计带有 ConardLi 标签的文章数。
const count = tags.reduce((sum , value) => sum + (value === 'ConardLi' ? 1 : 0), 0);
console.log(count);

.toArray()

toArray() 方法可以将迭代器的值转换为一个数组。

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 从最近的10篇博客文章列表中创建一个数组。
const arr = posts.values().take(10).toArray();

.forEach(fn)

类似数组的 forEach() 方法,forEach() 方法接受一个函数作为参数,然后在迭代器的每一个元素上调用这个函数。这个函数执行的是带有副作用的操作,会改变原本的迭代器,它不返回任何值。

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 获取发布了至少一篇博客文章的日期并记录下来。
const dates = new Set();
const forEach = posts.values().forEach((x) => dates.add(x.querySelector('time')));
console.log(dates);

.some(fn)

类似数组的 some() 方法,some() 方法接受一个断言函数作为参数。如果在应用该函数后,有任何一个迭代器的元素返回 true,那么这个方法就会返回 true

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 查找任何博客文章的文本内容(标题)是否包含 `ConardLi` 关键字。
posts.values().some((x) => x.textContent.includes('ConardLi'));

.every(fn)

类似数组的 every() 方法,every() 方法接受一个断言函数作为参数。如果在应用该函数后,迭代器的每个元素都返回 true,那么这个方法就会返回 true

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 检查所有博客文章的文本内容(标题)是否全部包含 `ConardLi` 关键词。
posts.values().every((x) => x.textContent.includes('ConardLi'));

.find(fn)

类似数组的 find() 方法,find() 方法接受一个断言函数作为参数。然后其会返回迭代器中第一个使函数返回 true 的元素,如果没有任何一个元素满足条件,那么返回 undefined

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 打印最新的博客文章中包含 `ConardLi` 关键词的文本内容(标题)。
console.log(posts.values().find((x) => x.textContent.includes('ConardLi')).textContent);

Iterator.from(object)

from() 是一个静态方法,接受一个对象作为参数。如果该对象已经是迭代器的实例,那么这个方法会直接返回它。如果该对象具有 Symbol.iterator 属性,意味着它是可迭代的,那么就会调用它的 Symbol.iterator 方法来获取迭代器,并由此方法返回。否则,会创建一个新的迭代器对象(该对象从 Iterator.prototype 继承并具有 next()return() 方法),该对象包装了这个对象并由此方法返回。

代码语言:javascript
复制
// 从博客存档页面中选择博客文章列表
const posts = document.querySelectorAll('li:not(header li)');

// 首先从帖子中创建一个迭代器。然后,记录包含 `ConardLi` 关键词的最新博客文章的文本内容(标题)。
console.log(Iterator.from(posts).find((x) => x.textContent.includes('ConardLi')).textContent);

最后

抖音前端架构团队目前放出不少新的 HC ,又看起会的小伙伴可以看看这篇文章:抖音前端架构团队正在寻找人才!FE/Client/Server/QA

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 code秘密花园 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Iterator 和数组的对比
  • .map(mapperFn)
  • .filter(filtererFn)
  • .take(limit)
  • .drop(limit)
  • .flatMap(mapperFn)
  • .reduce(reducer [, initialValue ])
  • .toArray()
  • .forEach(fn)
  • .some(fn)
  • .every(fn)
  • .find(fn)
  • Iterator.from(object)
  • 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档