对象、类与面向对象编程
迭代器与生成器
迭代器模式
1. 理解迭代器
迭代器模式提供了一种统一的方式来遍历不同的集合类型。在 JavaScript 中,迭代器是一个对象,它定义了一个标准的方式来产生一个值的序列。
javascript
// 基本迭代器协议
let iterator = {
next() {
return {
value: any,
done: boolean
};
}
};
// 可迭代协议
let iterable = {
[Symbol.iterator]() {
return iterator;
}
};
2. 创建自定义迭代器
javascript
// 实现一个范围迭代器
class RangeIterator {
constructor(start, end) {
this.current = start;
this.end = end;
}
[Symbol.iterator]() {
return this;
}
next() {
let value = this.current;
if (value <= this.end) {
this.current++;
return { value, done: false };
}
return { done: true };
}
}
// 使用范围迭代器
let range = new RangeIterator(1, 3);
for (let num of range) {
console.log(num); // 1, 2, 3
}
// 实现一个树结构迭代器
class TreeNode {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
*[Symbol.iterator]() {
// 中序遍历
if (this.left) yield* this.left;
yield this.value;
if (this.right) yield* this.right;
}
}
// 使用树迭代器
let tree = new TreeNode(1);
tree.left = new TreeNode(2);
tree.right = new TreeNode(3);
for (let value of tree) {
console.log(value); // 2, 1, 3
}
3. 内置可迭代对象
javascript
// 数组迭代
let arr = ['a', 'b', 'c'];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }
// Map迭代
let map = new Map([['name', 'John'], ['age', 30]]);
for (let [key, value] of map) {
console.log(`${key}: ${value}`);
}
// Set迭代
let set = new Set(['red', 'green', 'blue']);
for (let color of set) {
console.log(color);
}
生成器
1. 生成器基础
生成器是一种特殊的函数,可以在执行过程中暂停和恢复。
javascript
// 基本生成器
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
let gen = numberGenerator();
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 }
// 带参数的生成器
function* dialogueGenerator() {
const name = yield "What's your name?";
const age = yield "How old are you?";
return `Hello, ${name}! You are ${age} years old.`;
}
let dialogue = dialogueGenerator();
console.log(dialogue.next()); // { value: "What's your name?", done: false }
console.log(dialogue.next('John')); // { value: "How old are you?", done: false }
console.log(dialogue.next('30')); // { value: "Hello, John! You are 30 years old.", done: true }
2. 高级生成器模式
2.1 异步操作序列
javascript
// 模拟异步操作
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 异步任务执行器
function* taskGenerator() {
try {
console.log('Starting tasks...');
yield delay(1000);
console.log('Task 1 completed');
yield delay(1000);
console.log('Task 2 completed');
yield delay(1000);
console.log('All tasks completed');
} catch (err) {
console.error('Task failed:', err);
}
}
// 执行器函数
async function runGenerator(generator) {
const iterator = generator();
let result;
do {
result = await iterator.next();
} while (!result.done);
return result.value;
}
// 使用执行器
runGenerator(taskGenerator);
2.2 数据流处理
javascript
// 实现数据流管道
function* numberStream() {
yield* [1, 2, 3, 4, 5];
}
function* filter(iterator, predicate) {
for (const value of iterator) {
if (predicate(value)) {
yield value;
}
}
}
function* map(iterator, transform) {
for (const value of iterator) {
yield transform(value);
}
}
// 使用管道处理数据
const pipeline = map(
filter(numberStream(), n => n % 2 === 0),
n => n * 2
);
for (const value of pipeline) {
console.log(value); // 4, 8
}
3. 实际应用场景
3.1 分页数据加载
javascript
class DataLoader {
constructor(pageSize = 10) {
this.pageSize = pageSize;
this.currentPage = 0;
this.data = [];
}
async loadPage() {
// 模拟API调用
const response = await fetch(`/api/data?page=${this.currentPage}&size=${this.pageSize}`);
const data = await response.json();
return data;
}
async *loadAll() {
while (true) {
const pageData = await this.loadPage();
if (pageData.length === 0) break;
this.currentPage++;
yield* pageData;
}
}
}
// 使用示例
async function displayData() {
const loader = new DataLoader();
for await (const item of loader.loadAll()) {
console.log(item);
}
}
3.2 状态机实现
javascript
function* createStateMachine(states, initialState) {
let currentState = initialState;
while (true) {
const action = yield currentState;
const nextState = states[currentState][action];
if (nextState) {
currentState = nextState;
} else {
console.warn(`Invalid action "${action}" for state "${currentState}"`);
}
}
}
// 使用示例:交通信号灯
const trafficLightStates = {
red: { next: 'green' },
green: { next: 'yellow' },
yellow: { next: 'red' }
};
const trafficLight = createStateMachine(trafficLightStates, 'red');
console.log(trafficLight.next().value); // 'red'
console.log(trafficLight.next('next').value); // 'green'
console.log(trafficLight.next('next').value); // 'yellow'
console.log(trafficLight.next('next').value); // 'red'
迭代器与生成器的高级模式
1. 组合模式
javascript
// 组合多个迭代器
function* combine(...iterables) {
for (const iterable of iterables) {
yield* iterable;
}
}
// 使用示例
const numbers = [1, 2, 3];
const letters = ['a', 'b', 'c'];
const combined = combine(numbers, letters);
console.log([...combined]); // [1, 2, 3, 'a', 'b', 'c']
// 交替组合
function* alternate(...iterables) {
const iterators = iterables.map(i => i[Symbol.iterator]());
while (true) {
const results = iterators.map(i => i.next());
if (results.every(r => r.done)) break;
yield* results.map(r => r.value).filter(v => v !== undefined);
}
}
const alternated = alternate(numbers, letters);
console.log([...alternated]); // [1, 'a', 2, 'b', 3, 'c']
2. 异步迭代器
javascript
// 实现异步迭代器
class AsyncNumberGenerator {
constructor(start, end, delay = 1000) {
this.start = start;
this.end = end;
this.delay = delay;
}
async *[Symbol.asyncIterator]() {
for (let i = this.start; i <= this.end; i++) {
await new Promise(resolve => setTimeout(resolve, this.delay));
yield i;
}
}
}
// 使用异步迭代器
async function demo() {
const numbers = new AsyncNumberGenerator(1, 3);
for await (const num of numbers) {
console.log(num); // 每隔1秒输出:1, 2, 3
}
}
最佳实践
迭代器使用建议
- 使用生成器函数简化迭代器创建
- 注意处理异常情况
- 合理使用 return() 和 throw() 方法
生成器使用建议
- 使用生成器处理大数据集
- 实现异步操作序列
- 注意内存管理
性能考虑
- 避免无限迭代
- 适当使用缓存
- 考虑懒加载模式
注意事项
- 迭代器状态是一次性的
- 生成器函数的上下文会被保留
- 注意处理异步操作的错误
练习题
- 实现一个斐波那契数列生成器。
- 创建一个支持过滤和转换的数据流管道。
- 实现一个异步任务队列,使用生成器控制执行流程。
- 设计一个分页数据加载器,使用异步迭代器实现。