欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > ES6/ES11知识点 续五

ES6/ES11知识点 续五

2025/5/13 16:22:12 来源:https://blog.csdn.net/weixin_46282323/article/details/147726478  浏览:    关键词: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 构建等。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com