ES6的迭代器(Iterator)和生成器(Generator)

news/2025/1/13 7:34:19/

ES6引入了迭代器和生成器的概念,这两个特性为JavaScript带来了更强大的迭代和异步编程能力。本文将深入探讨ES6的迭代器和生成器,介绍它们的概念、用法以及在实际开发中的应用。

迭代器(Iterator)

迭代器(Iterator)是ES6引入的一种新的数据结构,它提供了一种统一的遍历机制,可以用来遍历各种不同类型的数据。迭代器的概念、作用和遍历原理如下所述:

1. 概念

迭代器是一种对象,它提供了一种顺序访问集合中每个元素的方式,而不暴露集合内部的表示。通过调用迭代器的next()方法,可以依次获取集合中的每个元素,并返回一个包含value和done属性的对象。value表示当前元素的值,done表示是否已经遍历完所有元素。

2. 作用

迭代器提供了一种统一的遍历机制,使得我们可以使用相同的方式来访问不同类型的数据结构。无论是数组、字符串、Set、Map还是自定义对象,只要实现了迭代器接口,就可以使用for...of循环或者手动调用next()方法来进行遍历。

3. 遍历原理

当我们使用for...of循环或者手动调用next()方法时,迭代器会按照预定的顺序依次返回集合中的每个元素。具体原理如下:

  • 首先,在需要进行遍历操作时,我们通过调用集合对象上的Symbol.iterator方法获取到该集合对象对应的默认迭代器。
  • 然后,在每次调用next()方法时,迭代器会执行相应的操作,并返回一个包含value和done属性的对象。
  • 如果done为false,则表示还有更多的元素需要遍历,此时value属性表示当前遍历到的值。
  • 如果done为true,则表示已经遍历完所有元素,此时value属性为undefined。

4. 使用示例

示例一:

let arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

在上面的例子中,我们首先通过调用数组arr上的Symbol.iterator方法获取到数组的默认迭代器。然后,我们通过调用next()方法依次获取数组中的每个元素。在每次调用next()方法时,迭代器会返回一个包含当前元素值和是否遍历完所有元素的对象。

通过迭代器,我们可以方便地遍历不同类型的数据结构,并且可以自定义实现迭代器接口来实现特定的遍历方式。这为我们在实际开发中提供了更大的灵活性和便利性。

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内。

详见 # ES6之原始数据类型Symbol

示例二:

自定义迭代器遍历斐波那契数列:

let fibonacci = {[Symbol.iterator]() {let pre = 0,cur = 1return {next() {[pre, cur] = [cur, pre + cur]return { value: cur, done: false }}}}
}
for (let num of fibonacci) {if (num > 1000) breakconsole.log(num)
}// 输出:
// 1
// 2
// 3
// 5
// ...

在这个示例中,我们通过自定义迭代器接口来遍历斐波那契数列。在每次迭代时,迭代器会计算下一个斐波那契数,并返回给遍历循环。

简单原理实现示例

原理简单实现示例:

function createIterator(arr) {let index = 0return {next() {if (index < arr.length) {return { value: arr[index++], done: false }} else {return { value: undefined, done: true }}}}
}
let iterator = createIterator([1, 2, 3])
console.log(iterator.next()) // { value: 1, done: false }
console.log(iterator.next()) // { value: 2, done: false }
console.log(iterator.next()) // { value: 3, done: false }
console.log(iterator.next()) // { value: undefined, done: true }

在这个示例中,我们通过自定义函数createIterator来实现一个迭代器。该函数返回一个包含next()方法的对象,每次调用next()方法时,会依次返回数组中的每个元素。

生成器(Generator)

生成器(Generator)是ES6引入的一种特殊的函数,它可以通过yield关键字来暂停函数的执行,并返回一个包含value和done属性的对象。生成器的概念、作用和原理如下所述:

1. 概念

生成器是一种特殊的函数,它使用function*语法进行定义。在生成器函数内部,可以使用yield关键字来暂停函数的执行,并返回一个包含value和done属性的对象。value表示yield表达式的值,done表示函数是否已经执行完毕。

2. 作用

生成器提供了一种更灵活、更可控的方式来处理异步编程。通过使用yield关键字,我们可以在函数执行过程中暂停和恢复,并且可以将异步操作以同步方式编写和理解。

3. 原理

当我们调用生成器函数时,实际上并不会立即执行函数体内部的代码。而是返回一个迭代器对象,该迭代器对象实现了next()方法。每次调用next()方法时,生成器会从上一次暂停的位置继续执行代码,直到遇到下一个yield关键字或者函数结束。

示例

下面通过一个例子来说明生成器的使用:

function* generatorFunc() {yield 'Hello';yield 'World';
}
let generator = generatorFunc();
console.log(generator.next()); // { value: 'Hello', done: false }
console.log(generator.next()); // { value: 'World', done: false }
console.log(generator.next()); // { value: undefined, done: true }

在上面的例子中,我们定义了一个生成器函数generatorFunc。在函数体内部,我们使用yield关键字来暂停函数的执行,并返回一个包含value和done属性的对象。通过调用生成器函数,我们可以获取到一个迭代器对象generator。在每次调用next()方法时,生成器会从上一次暂停的位置继续执行代码,并返回相应的值。 除了简单的示例,生成器还可以应用于异步编程中。

下面是一个使用生成器和Promise结合实现异步流程控制的示例

function* asyncFunc() {let result1 = yield asyncTask1()let result2 = yield asyncTask2(result1)return result2
}
function asyncTask1() {return new Promise((resolve) => {setTimeout(() => resolve('Result 1'), 1000)})
}
function asyncTask2(arg) {return new Promise((resolve) => {setTimeout(() => resolve(`Result 2 with ${arg}`), 1000)})
}
function runAsync(generator) {let iterator = generator()function iterate({ value, done }) {if (done) return valuereturn Promise.resolve(value).then((res) => iterate(iterator.next(res))).catch((err) => iterator.throw(err))}try {return iterate(iterator.next())} catch (err) {return Promise.reject(err)}
}
runAsync(asyncFunc).then((result) => console.log(result)) // 'Result 2 with Result 1'.catch((error) => console.error(error))

在这个示例中,我们定义了一个异步生成器函数asyncFunc。在函数体内部,我们使用yield关键字来暂停函数的执行,并通过Promise来处理异步操作。通过调用runAsync函数,我们可以运行异步生成器,并获取到最终的结果。 通过生成器,我们可以以同步的方式编写异步代码,提高代码的可读性和可维护性。生成器为我们处理异步流程控制提供了更加优雅和简洁的解决方案。

通过生成器和Promise的结合,我们可以以同步的方式编写异步代码,提高代码的可读性和可维护性。

总结

ES6的迭代器和生成器为JavaScript带来了更强大的迭代和异步编程能力。迭代器提供了一种顺序访问集合中每个元素的方式,而生成器则允许函数在执行过程中暂停和恢复。它们在实际开发中有着广泛的应用,可以用于自定义遍历方式、简化异步流程控制等场景。通过深入了解迭代器和生成器,我们可以更好地利用它们来提升代码的质量和效率。


http://www.ppmy.cn/news/1246764.html

相关文章

走近“中国深度-深海探索主题展”,带你探索深海远洋

深海&#xff0c;自古以来给予了人类无限的遐想&#xff0c;随着时代的进步和科学的发展&#xff0c;海洋的神秘面纱被一点点揭开&#xff0c;呈现在我们面前的是一个资源宝库&#xff0c;“可上九天揽月&#xff0c;可下五洋捉鳖”已经成为现实&#xff0c;21世纪是海洋的世纪…

大模型fine-tune 微调

大模型的 Fine-tune 我们对技术的理解&#xff0c;要比技术本身更加重要。 正如我在《大模型时代的应用创新范式》一文中所说&#xff0c;大模型会成为AI时代的一项基础设施。 作为像水、电一样的基础设施&#xff0c;预训练大模型这样的艰巨任务&#xff0c;只会有少数技术…

AI数字人与虚拟人:区别与应用场景

随着人工智能和虚拟技术的不断发展&#xff0c;AI数字人和虚拟人成为了数字世界中的两个重要概念。本文将介绍AI数字人和虚拟人的区别&#xff0c;并探讨它们在不同领域的应用场景。 一、AI数字人与虚拟人的区别 定义和概念&#xff1a; AI数字人&#xff1a;是利用人工智能技术…

easyExcel 注解开发 快速以及简单上手 以及包含工具类

easyExcel 简单快速使用 1. mevan 这里版本我这里选的是 poi 4.1.2和 ali的easyexcel 的 3.3.1。 因为阿里easy是根据poi的依赖开发的有关系&#xff0c;两者需要对应要不然就会有很多bug和错误在运行时发生。需要版本对应&#xff0c;然而就是easy的代码也会有bug这个版本是比…

【数据库】基于排序算法的去重,集合与包的并,差,交,连接操作实现原理,执行代价以及优化

基于两趟排序的其它操作 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏…

房屋租赁出售经纪人入驻小程序平台

一款专为房屋中介开发的小程序平台&#xff0c;支持独立部署&#xff0c;源码交付&#xff0c;数据安全无忧。 核心功能&#xff1a;房屋出租、经纪人独立后台、分佣后台、楼盘展示、房型展示、在线咨询、地址位置配套设施展示。 程序已被很多房屋交易中介体验使用过&#x…

在 Ubuntu 上安装最新版的 Calibre

目录 前言 方法1&#xff1a;从 Ubuntu 的仓库安装 Calibre 卸载 Calibre 方法2&#xff1a;获取最新版本的 Calibre 卸载 Calibre 结语 前言 Calibre 是一款自由开源的电子书软件。下面介绍如何在 Ubuntu Linux 上安装它。 作为电子书管理的瑞士军刀&#xff0c;Calibre …

vue3安装eslint和prettier,最简单的步骤

第1步&#xff1a; 安装eslint yarn add eslint -D 第2步&#xff1a; 在根文件夹中&#xff0c;创建.eslintrc.js文件 第3步&#xff1a; 在package.json文件中新增命令 "lint": "eslint --fix --ext .ts,.tsx,.vue src --quiet","prettier"…