当前位置: 首页 > 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 构建等。
http://www.xdnf.cn/news/307027.html

相关文章:

  • 单调栈算法精解(Java实现):从原理到高频面试题
  • [250504] Moonshot AI 发布 Kimi-Audio:开源通用音频大模型,驱动多模态 AI 新浪潮
  • Android数据库全栈开发实战:Room+SQLCipher+Hilt企业级应用构建
  • 【计算机网络】TCP/IP四层模型是什么?与OSI七层模型哪些区别?
  • 提示词的 嵌入空间优化
  • ECMAScript 6(ES6):JavaScript 现代化的革命性升级
  • 使用蚁群算法求解VRPTW问题
  • 信息系统项目管理工程师备考计算类真题讲解十三
  • 光纤失效模式及其影响
  • n8n 与智能体构建:开发自动化 AI 作业的基础平台
  • 单例模式的实现方法
  • Android SDK 国内镜像及配置方法(2025最新,包好使!)
  • MySQL同步ES的6种方案!
  • 74LS138译码器的编址技术
  • 存储系列知识
  • YOLO8之学习指南
  • 行业黑化.新平面
  • 系统学习算法:动态规划(斐波那契+路径问题)
  • 第2章——springboot核心机制
  • Spring Boot Validation实战详解:从入门到自定义规则
  • DXFViewer进行中2 -> 直线 解析+渲染 ✅已完成
  • 2025 RSAC|大语言模型应用风险与厂商攻防新策略
  • C#经典算法面试题
  • 【STM32 学习笔记】EXTI外部中断
  • 单片机-STM32部分:5、STM32CubeMX实现HAL点灯
  • Python之内省与反射应用
  • 多语言笔记系列:Polyglot Notebooks 中使用扩展库
  • Kotlin Android开发过渡指南
  • 【笔记】【B站课程 pytorch】梯度下降模型
  • 【2025年】基于电脑的jdk1.8通过idea创建springboot2.x版本(非常简洁快速)