当前位置: 首页 > news >正文

ES6/ES11知识点 续五

迭代器【Iterator】

ES6 中的**迭代器(Iterator)**是 JavaScript 的一种协议,它定义了对象如何被逐个访问。迭代器与 for…of、扩展运算符、解构赋值等语法密切相关。

📘 迭代器工作原理

ES6 迭代器的工作原理基于两个核心机制:

🌟 可迭代协议(Iterable Protocol)

如果一个对象实现了 Symbol.iterator 方法,并返回一个迭代器对象,那么它就是可迭代的(Iterable),可以用于:

  • for…of
  • 解构赋值(如 [a, b] = iterable)
  • … 扩展运算符
  • Array.from()
const iterable = {[Symbol.iterator]() {let i = 0;return {next() {return i < 3 ? { value: i++, done: false } : { done: true };}};}
};for (const val of iterable) {console.log(val); // 0 1 2
}

⚙️迭代器协议(Iterator Protocol)

迭代器对象必须具有 next() 方法,每次调用返回一个对象:

{ value: any, done: boolean }

含义:

  • value: 当前值
  • done: false: 迭代未结束
  • done: true: 迭代结束

当 done: true 时,value 可选,将被忽略

🔄 for…of 背后的流程

等价于下面这个展开流程:

const iterator = iterable[Symbol.iterator]();
let result = iterator.next();
while (!result.done) {const value = result.value;// 执行代码块result = iterator.next();
}

📦 内置可迭代对象如何实现?

例如数组:

const arr = [10, 20, 30];
const iter = arr[Symbol.iterator]();iter.next(); // { value: 10, done: false }
iter.next(); // { value: 20, done: false }

浏览器底层实现了数组的 Symbol.iterator 方法,它会返回一个迭代器对象。

🧠 迭代器的本质理解

  • Symbol.iterator 是告诉 JavaScript:我可以被 for…of 遍历
  • 返回的迭代器对象 next() 方法控制了“值从哪里来”和“什么时候结束”
  • 你也可以用 yield(生成器)简化构建逻辑

🛠️ 手动创建一个迭代器

function createIterator(arr) {let index = 0;return {next() {if (index < arr.length) {return { value: arr[index++], done: false };} else {return { value: undefined, done: true };}}};
}const it = createIterator(['a', 'b', 'c']);
console.log(it.next()); // { value: 'a', done: false }
console.log(it.next()); // { value: 'b', done: false }
console.log(it.next()); // { value: 'c', done: false }
console.log(it.next()); // { value: undefined, done: true }

🚀 使对象可被 for…of 遍历

const iterableObj = {data: [10, 20, 30],[Symbol.iterator]() {let i = 0;const data = this.data;return {next() {return i < data.length? { value: data[i++], done: false }: { done: true };}};}
};for (const val of iterableObj) {console.log(val);
}
// 输出:10 20 30

📦 内置可迭代对象

类型 可迭代? 示例
数组 ✅ for (let x of [1,2,3])
字符串 ✅ for (let c of ‘abc’)
Set / Map ✅ for (let e of new Set())
arguments ✅ for (let a of arguments)
DOM NodeList ✅ for (let el of nodelist)
普通对象 ❌ { a: 1 } ❌不能直接 for…of

🧙‍♂️ 配合生成器使用(语法糖)

function* gen() {yield 1;yield 2;yield 3;
}
const g = gen();
console.log(g.next()); // { value: 1, done: false }for (const x of gen()) {console.log(x); // 1, 2, 3
}

✅ 判断是否可迭代

function isIterable(obj) {return typeof obj[Symbol.iterator] === 'function';
}

类数组对象添加自定义迭代器

方式一

const arrayLike = {0: 'a',1: 'b',2: 'c',length: 3,[Symbol.iterator]() {let index = 0;return {next: () => {return index < this.length? { value: this[index++], done: false }: { done: true };}};}
};for (const val of arrayLike) {console.log(val); // 输出:a, b, c
}

方式二

使用生成器方式更优雅

const arrayLike = {0: 'x',1: 'y',2: 'z',length: 3,*[Symbol.iterator]() {for (let i = 0; i < this.length; i++) {yield this[i];}}
};for (const val of arrayLike) {console.log(val); // 输出:x, y, z
}

生成器

在 ES6 中,生成器(Generator)是一种特殊的函数,能控制函数的执行流程,支持按需产出(惰性求值),适合处理迭代、异步、状态机等场景。

🧱 基本语法

function* myGenerator() {yield 1;yield 2;yield 3;
}
  • 使用 function* 定义生成器函数(注意星号 *)。
  • 内部使用 yield 表达式产生值。
  • 调用生成器函数返回的是一个迭代器对象。

🚀 调用与执行流程

const gen = myGenerator();console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
  • 每次调用 next(),函数执行到下一个 yield 停下来,返回一个 { value, done } 对象。
  • 最后 done: true 表示完成。

🔁 配合 for…of

for (const val of myGenerator()) {console.log(val); // 输出:1, 2, 3
}

🧠 生成器的高级用法

✅ 接收外部值

function* gen() {const a = yield 1;const b = yield a + 2;return b;
}const it = gen();console.log(it.next());       // { value: 1, done: false }
console.log(it.next(10));     // { value: 12, done: false }
console.log(it.next(100));    // { value: 100, done: true }
  • yield 表达式可以接收传入的值,作为上一个 yield 的返回值。

🛠 典型应用场景

生成无限序列

function* idGenerator() {let id = 0;while (true) yield id++;
}const ids = idGenerator();
console.log(ids.next().value); // 0
console.log(ids.next().value); // 1

自定义迭代器

const obj = {*[Symbol.iterator]() {yield 1;yield 2;yield 3;}
};for (const x of obj) {console.log(x); // 输出:1, 2, 3
}

与异步协程结合(配合 async/await 或库如 co)

生成器可用于构造异步流程控制逻辑,尽管现在大多数场景被 async/await 替代。

yield* 的作用(委托子生成器)或生成器和 async/await 的区别

🔄 yield*:委托另一个生成器或可迭代对象

yield* 表达式可以将执行控制权交给另一个生成器或可迭代对象,就像“嵌套展开”。

✅ 示例 1:委托另一个生成器

function* inner() {yield 'a';yield 'b';
}function* outer() {yield 'start';yield* inner(); // 委托 inner 生成器yield 'end';
}for (const val of outer()) {console.log(val); // 输出:start, a, b, end
}

✅ 示例 2:委托数组

function* gen() {yield* [1, 2, 3];
}console.log([...gen()]); // [1, 2, 3]

⚙️ 生成器 vs async/await

特性生成器(Generator)async/await
关键字function*, yieldasync function, await
控制流程方式手动通过 .next() 推进自动推进
异步支持不直接支持(需配合库)原生支持 Promise
返回值迭代器对象Promise
适合场景同步流程控制、数据生成异步流程控制

🔧 示例对比

1️⃣ 生成器实现异步流程(配合库如 co)

function* asyncTask() {const data = yield fetch('...');console.log(data);
}
// 需要外部 runner 自动推进

2️⃣ async/await 简洁实现

async function asyncTask() {const data = await fetch('...');console.log(data);
}

异步生成器 async function* 的基本用法

async function* asyncGenerator() {let i = 0;while (i < 3) {await new Promise(resolve => setTimeout(resolve, 1000)); // 模拟异步操作yield i++;}
}// 使用 for await...of 来消费异步生成器
(async () => {for await (const val of asyncGenerator()) {console.log(val); // 每秒输出一个数字:0, 1, 2}
})();

异步分页加载

async function* fetchPages(total) {for (let page = 1; page <= total; page++) {const data = await fetch(`https://api.example.com/data?page=${page}`);const json = await data.json();yield json.items;}
}(async () => {for await (const items of fetchPages(3)) {console.log('Page items:', items);}
})();

总结

  • yield* 是 生成器中的“合并子迭代器”工具。
  • async/await 是语法更清晰的异步生成器替代方案,自动推进,适合处理 Promise。
  • 生成器仍适用于同步状态控制、迭代器构造、无限序列、DSL 构建等。

相关文章:

  • 动手学深度学习12.1. 编译器和解释器-笔记练习(PyTorch)
  • 「Mac畅玩AIGC与多模态21」开发篇17 - 多字段判断与多路径分支工作流示例
  • Hello Robot 推出Stretch 3移动操作机器人 提升开源与可用性
  • 大搜车:借力 OB Cloud 实现经销商管理系统SRP的技术升级
  • 探索Hello Robot开源移动操作机器人Stretch 3的新技术亮点与市场定位
  • 蓝肽子序列--字符串+最长子序列的dp
  • 虚拟现实视频播放器 2.6.1 | 支持多种VR格式,提供沉浸式观看体验的媒体播放器
  • 在 Laravel 12 中实现 WebSocket 通信
  • Redis 7.0中5种新特性及实战应用
  • AI Agent 入门指南:从 LLM 到智能体
  • 人工智能如何革新数据可视化领域?探索未来趋势
  • 【编程干货】本地用 Ollama + LLaMA 3 实现 Model Context Protocol(MCP)对话服务
  • 手撕算法(1)
  • Python-map从基础到进阶
  • 42 python http之urllib库
  • Vue 自定义指令输入校验过滤
  • 【前缀和】矩阵区域和
  • Hadoop架构再探讨
  • 【MongoDB篇】MongoDB的聚合框架!
  • python刷题笔记:三目运算符的写法
  • 李云泽:支持设立新的金融资产投资公司,今天即将批复一家
  • 微软通讯软件Skype正式停止运营:斥资85亿美元购入,月活用户曾超3亿
  • 山东滕州市醉驾交通事故肇事人员已被刑拘
  • 马斯克的胜利?OpenAI迫于压力放弃营利性转型计划
  • 新闻分析:电影关税能“让好莱坞再次伟大”?
  • 多省份晒出“五一”旅游“成绩单”:北京游客接待量、旅游消费创历史新高