概念
迭代器
- 定义 :迭代器是实现了
next()
方法的对象,每次调用返回{ value: any, done: boolean }
,用于按需遍历数据集合。value
代表当前迭代的值,done
是一个布尔值,true
表示迭代结束,false
表示还有更多值可迭代。 - 可迭代对象 :任何实现了
Symbol.iterator
方法的对象均可被for...of
遍历(如数组、Set、Map)。 - 核心方法:
scss
const iterator = {
next() { /* 返回下一个值 */ },
return() { /* 提前终止迭代 */ },
throw() { /* 抛出异常 */ }
};
生成器
- 定义 :生成器是使用
function*
定义的函数,通过yield
暂停执行并按需生成值,返回一个符合迭代器协议的对象。 - 特性:
-
- 支持双向通信(通过
next(value)
传递参数)。 - 天然支持异步操作(结合
yield
和 Promise)。
- 支持双向通信(通过
javascript
function* myGenerator() {
yield 1;
yield 2;
}
Symbol.iterator
Symbol.iterator
是 JavaScript 中的一个内置符号(全局的、独一无二的)。
它主要用于定义对象的默认迭代器,使得对象能借助 for...of
循环等迭代机制进行遍历。
当一个对象实现了以 Symbol.iterator
为键的方法时,这个对象就被称为 "可迭代对象",该方法会返回一个迭代器对象。
自定义实现以及使用场景
迭代器
基础实现
1. 通过类实现迭代器
定义一个类并实现 [Symbol.iterator]()
方法,返回包含 next()
方法的迭代器对象:
kotlin
class NumberRange {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let current = this.start;
return {
next: () => {
return current <= this.end
? { value: current++, done: false }
: { done: true };
}
};
}
}
核心逻辑:
next()
每次返回{ value, done }
对象,done
为true
时终止迭代;- 示例:遍历
new NumberRange(1, 5)
会输出 1 到 5。
2. 通过普通对象实现
为普通对象添加 Symbol.iterator
方法,支持 for...of
遍历:
ini
const colors = { blue: "蓝色", green: "绿色", yellow: "黄色" };
colors[Symbol.iterator] = function() {
const keys = Object.keys(this);
let index = 0;
return {
next: () => {
return index < keys.length
? { value: this[keys[index++]], done: false }
: { done: true };
}
};
};
- 应用场景 :遍历对象键值对,如
for (const val of colors)
输出颜色值。
高级实现技巧
1. 生成器函数简化实现
使用 function*
生成器自动管理迭代状态,无需手动维护 next()
:
vbnet
const obj = { a: 1, b: 2 };
obj[Symbol.iterator] = function* () {
for (const key of Object.keys(this)) {
yield { key, value: this[key] };
}
};
- 优势 :代码更简洁,自动处理
value
和done
状态。
2. 支持提前终止
为迭代器添加 return()
方法,处理 break
或错误中断:
javascript
class SafeRange {
[Symbol.iterator]() {
let current = this.start;
return {
next() { /* ... */ },
return() {
console.log('迭代提前终止');
return { done: true };
}
};
}
}
触发条件 :当循环被 break
、return
或抛出错误时调用。
应用场景
1. 自定义数据结构迭代
实现双向迭代器(如链表或树结构):
kotlin
class BidirectionalRange {
constructor(start, end) {
this.current = start;
this.start = start;
this.end = end;
}
[Symbol.iterator]() { return this; }
next() {
return this.current <= this.end
? { value: this.current++, done: false }
: { done: true };
}
prev() {
return this.current > this.start
? { value: --this.current, done: false }
: { done: true };
}
}
- 用途:支持正向和逆向遍历。
2. 惰性求值与无限序列
生成无限斐波那契数列:
ini
function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
特点:按需生成值,无需预加载全部数据。
生成器
基础实现
1. 生成器函数定义
生成器函数通过 function*
声明,并通过 yield
关键字暂停执行:
javascript
function* foo(index) {
while (index < 2) {
yield index;
index++;
}
}
const iterator = foo(0);
console.log(iterator.next().value);
// 0
console.log(iterator.next().value);
// 1
2.自定义迭代器
通过 Symbol.iterator
将生成器绑定到对象,使其可被 for...of
遍历:
vbnet
const colors = { blue: "蓝色", green: "绿色" };
colors[Symbol.iterator] = function* () {
for (const key of Object.keys(this)) {
yield { key, value: this[key] }; // 返回键值对
}
};
// 遍历结果:{ key: 'blue', value: '蓝色' }, { key: 'green', value: '绿色' }
高级应用技巧
1. 双向通信
通过 next()
向生成器传递参数,动态修改执行流程:
javascript
function* dialog() {
const name = yield "你的名字?";
const hobby = yield "你的爱好?";
return `${name}喜欢${hobby}`;
}
const chat = dialog();
console.log(chat.next().value); // "你的名字?"
console.log(chat.next("小明").value); // "你的爱好?"
console.log(chat.next("编程").value); // "小明喜欢编程"
应用场景:用户输入交互、动态配置。
2. 惰性求值与无限序列
生成器按需生成数据,节省内存:
ini
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 0, 1, 1, 2, 3, 5...
3. 异步流程控制
结合 Promise
实现同步风格的异步代码:
scss
function* asyncTask() {
const data = yield fetchData();
const processed = yield processData(data);
return saveData(processed);
}
// 自动执行器
function run(generator) {
const gen = generator();
function handle(result) {
if (result.done) return result.value;
return result.value.then(data => handle(gen.next(data)));
}
return handle(gen.next());
}
应用场景
1. 分页数据加载
按需逐页获取 API 数据:
ini
function* fetchPaginatedData(apiUrl) {
let page = 1;
while (true) {
const response = yield fetch(`${apiUrl}?page=${page}`);
const data = yield response.json();
if (data.length === 0) break;
yield data;
page++;
}
}
- 适用场景:大数据分页、动态加载。
2. 状态机
实现循环状态切换(如交通灯):
javascript
function* trafficLight() {
while (true) {
yield 'Green';
yield 'Yellow';
yield 'Red';
}
}
3. 文件分段读取
逐块处理大文件,避免内存溢出:
ini
const fs = require('fs');
function* readFileByChunks(filePath, chunkSize) {
const buffer = Buffer.alloc(chunkSize);
let position = 0;
const fd = fs.openSync(filePath, 'r');
while (true) {
const bytesRead = fs.readSync(fd, buffer, 0, chunkSize, position);
if (bytesRead === 0) break;
yield buffer.slice(0, bytesRead);
position += bytesRead;
}
fs.closeSync(fd);
}