Search K
Appearance
Appearance
📊 SEO元描述:2024年最新ES6迭代器和生成器教程,详解Iterator接口、Generator函数、yield关键字、自定义迭代器实现。包含完整实战案例,适合JavaScript开发者掌握高级异步编程。
核心关键词:ES6迭代器生成器2024、Iterator接口、Generator函数、yield关键字、自定义迭代器、JavaScript异步编程
长尾关键词:Iterator怎么用、Generator函数详解、yield关键字用法、JavaScript迭代器实现、生成器异步编程应用
通过本节ES6迭代器和生成器教程,你将系统性掌握:
为什么需要迭代器和生成器?这是现代JavaScript数据处理和异步编程的核心问题。迭代器提供了统一的遍历接口,生成器则提供了强大的流程控制能力,也是ES6+现代JavaScript的重要特性。
💡 核心原则:迭代器让遍历变得统一,生成器让流程控制变得优雅
Iterator接口是ES6引入的遍历标准,为各种数据结构提供了统一的访问机制。
// 🎉 Iterator接口详解
console.log('=== Iterator基本概念 ===');
// 1. Iterator接口的基本结构
function createSimpleIterator(array) {
let index = 0;
return {
next() {
if (index < array.length) {
return {
value: array[index++],
done: false
};
} else {
return {
done: true
};
}
}
};
}
const iterator = createSimpleIterator([1, 2, 3]);
console.log('第一次调用:', iterator.next()); // {value: 1, done: false}
console.log('第二次调用:', iterator.next()); // {value: 2, done: false}
console.log('第三次调用:', iterator.next()); // {value: 3, done: false}
console.log('第四次调用:', iterator.next()); // {done: true}
// 2. 内置的可迭代对象
console.log('\n=== 内置可迭代对象 ===');
// 数组的迭代器
const arr = [1, 2, 3];
const arrIterator = arr[Symbol.iterator]();
console.log('数组迭代器:');
console.log(arrIterator.next()); // {value: 1, done: false}
console.log(arrIterator.next()); // {value: 2, done: false}
// 字符串的迭代器
const str = 'hello';
const strIterator = str[Symbol.iterator]();
console.log('字符串迭代器:');
console.log(strIterator.next()); // {value: 'h', done: false}
console.log(strIterator.next()); // {value: 'e', done: false}
// Set的迭代器
const set = new Set([1, 2, 3]);
const setIterator = set[Symbol.iterator]();
console.log('Set迭代器:');
console.log(setIterator.next()); // {value: 1, done: false}
// Map的迭代器
const map = new Map([['a', 1], ['b', 2]]);
const mapIterator = map[Symbol.iterator]();
console.log('Map迭代器:');
console.log(mapIterator.next()); // {value: ['a', 1], done: false}
// 3. 自定义可迭代对象
console.log('\n=== 自定义可迭代对象 ===');
class NumberSequence {
constructor(start, end, step = 1) {
this.start = start;
this.end = end;
this.step = step;
}
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
const step = this.step;
return {
next() {
if (current <= end) {
const value = current;
current += step;
return { value, done: false };
} else {
return { done: true };
}
}
};
}
}
const sequence = new NumberSequence(1, 10, 2);
console.log('自定义序列遍历:');
for (const num of sequence) {
console.log(' ', num); // 1, 3, 5, 7, 9
}
// 可以多次遍历
console.log('转为数组:', [...sequence]); // [1, 3, 5, 7, 9]
// 4. 迭代器的实际应用:分页数据处理
console.log('\n=== 分页数据处理 ===');
class PaginatedData {
constructor(data, pageSize = 3) {
this.data = data;
this.pageSize = pageSize;
}
[Symbol.iterator]() {
let index = 0;
const data = this.data;
const pageSize = this.pageSize;
return {
next() {
if (index < data.length) {
const page = data.slice(index, index + pageSize);
index += pageSize;
return {
value: {
page: Math.ceil(index / pageSize),
data: page,
hasMore: index < data.length
},
done: false
};
} else {
return { done: true };
}
}
};
}
}
const userData = [
'User1', 'User2', 'User3', 'User4', 'User5',
'User6', 'User7', 'User8', 'User9', 'User10'
];
const paginatedUsers = new PaginatedData(userData, 3);
console.log('分页数据处理:');
for (const pageInfo of paginatedUsers) {
console.log(`第${pageInfo.page}页:`, pageInfo.data, `还有更多: ${pageInfo.hasMore}`);
}
// 5. 迭代器的组合和转换
console.log('\n=== 迭代器组合和转换 ===');
class IteratorUtils {
static map(iterable, mapFn) {
return {
[Symbol.iterator]() {
const iterator = iterable[Symbol.iterator]();
return {
next() {
const result = iterator.next();
if (result.done) {
return result;
}
return {
value: mapFn(result.value),
done: false
};
}
};
}
};
}
static filter(iterable, filterFn) {
return {
[Symbol.iterator]() {
const iterator = iterable[Symbol.iterator]();
return {
next() {
while (true) {
const result = iterator.next();
if (result.done) {
return result;
}
if (filterFn(result.value)) {
return result;
}
}
}
};
}
};
}
static take(iterable, count) {
return {
[Symbol.iterator]() {
const iterator = iterable[Symbol.iterator]();
let taken = 0;
return {
next() {
if (taken >= count) {
return { done: true };
}
taken++;
return iterator.next();
}
};
}
};
}
}
const numbers = new NumberSequence(1, 100);
const evenNumbers = IteratorUtils.filter(numbers, x => x % 2 === 0);
const doubledEvens = IteratorUtils.map(evenNumbers, x => x * 2);
const firstFive = IteratorUtils.take(doubledEvens, 5);
console.log('组合迭代器结果:', [...firstFive]); // [4, 12, 20, 28, 36]Generator函数是ES6引入的特殊函数,可以暂停和恢复执行,是实现迭代器的简洁方式。
// 🎉 Generator函数详解
console.log('=== Generator基本语法 ===');
// 1. Generator函数的定义和调用
function* simpleGenerator() {
console.log('Generator开始执行');
yield 1;
console.log('第一个yield后继续');
yield 2;
console.log('第二个yield后继续');
yield 3;
console.log('Generator执行完毕');
return 'done';
}
const gen = simpleGenerator();
console.log('Generator对象:', gen);
console.log('第一次next:', gen.next());
console.log('第二次next:', gen.next());
console.log('第三次next:', gen.next());
console.log('第四次next:', gen.next());
// 2. yield表达式的双向通信
console.log('\n=== yield双向通信 ===');
function* communicationGenerator() {
console.log('Generator启动');
const input1 = yield 'first';
console.log('接收到输入1:', input1);
const input2 = yield 'second';
console.log('接收到输入2:', input2);
return 'finished';
}
const commGen = communicationGenerator();
console.log('启动:', commGen.next());
console.log('发送hello:', commGen.next('hello'));
console.log('发送world:', commGen.next('world'));
// 3. Generator实现斐波那契数列
console.log('\n=== 斐波那契数列Generator ===');
function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log('斐波那契数列前10项:');
for (let i = 0; i < 10; i++) {
console.log(` F(${i}):`, fib.next().value);
}
// 4. Generator实现无限序列
console.log('\n=== 无限序列Generator ===');
function* infiniteSequence(start = 0, step = 1) {
let current = start;
while (true) {
yield current;
current += step;
}
}
function* take(generator, count) {
let taken = 0;
for (const value of generator) {
if (taken >= count) break;
yield value;
taken++;
}
}
const evenNumbers = infiniteSequence(0, 2);
const first10Evens = take(evenNumbers, 10);
console.log('前10个偶数:', [...first10Evens]);
// 5. Generator的错误处理
console.log('\n=== Generator错误处理 ===');
function* errorHandlingGenerator() {
try {
yield 'normal value';
yield 'another value';
} catch (error) {
console.log('Generator内部捕获错误:', error.message);
yield 'error handled';
}
yield 'final value';
}
const errorGen = errorHandlingGenerator();
console.log('正常执行:', errorGen.next());
console.log('抛出错误:', errorGen.throw(new Error('外部错误')));
console.log('继续执行:', errorGen.next());
// 6. Generator的提前结束
console.log('\n=== Generator提前结束 ===');
function* returnGenerator() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
const returnGen = returnGenerator();
console.log('第一次next:', returnGen.next());
console.log('第二次next:', returnGen.next());
console.log('调用return:', returnGen.return('提前结束'));
console.log('后续next:', returnGen.next()); // done: true
// 7. Generator委托(yield*)
console.log('\n=== Generator委托 ===');
function* innerGenerator() {
yield 'inner1';
yield 'inner2';
return 'inner done';
}
function* outerGenerator() {
yield 'outer start';
const result = yield* innerGenerator();
console.log('内部Generator返回值:', result);
yield 'outer end';
}
const delegateGen = outerGenerator();
console.log('委托Generator执行:');
let result = delegateGen.next();
while (!result.done) {
console.log(' ', result.value);
result = delegateGen.next();
}
// 8. 实际应用:状态机
console.log('\n=== 状态机应用 ===');
function* trafficLightStateMachine() {
while (true) {
console.log('🔴 红灯 - 停止');
yield 'red';
console.log('🟢 绿灯 - 通行');
yield 'green';
console.log('🟡 黄灯 - 准备停止');
yield 'yellow';
}
}
const trafficLight = trafficLightStateMachine();
console.log('交通灯状态机:');
for (let i = 0; i < 6; i++) {
const state = trafficLight.next().value;
console.log(` 当前状态: ${state}`);
}yield关键字是Generator函数的核心,提供了强大的流程控制能力。
// 🎉 yield关键字详解
console.log('=== yield基本用法 ===');
// 1. yield作为表达式
function* yieldExpressionDemo() {
const a = yield 'first';
console.log('a =', a);
const b = yield 'second';
console.log('b =', b);
return a + b;
}
const yieldGen = yieldExpressionDemo();
console.log('启动:', yieldGen.next());
console.log('传入10:', yieldGen.next(10));
console.log('传入20:', yieldGen.next(20));
// 2. yield*委托给其他可迭代对象
console.log('\n=== yield*委托 ===');
function* delegateToArray() {
yield* [1, 2, 3];
yield* 'hello';
yield* new Set([4, 5, 6]);
}
console.log('委托给多种可迭代对象:', [...delegateToArray()]);
// 3. 异步Generator应用
console.log('\n=== 异步流程控制 ===');
function* asyncFlowControl() {
console.log('开始异步流程');
try {
const user = yield fetch('/api/user');
console.log('用户数据获取成功');
const profile = yield fetch(`/api/profile/${user.id}`);
console.log('用户资料获取成功');
const posts = yield fetch(`/api/posts/${user.id}`);
console.log('用户文章获取成功');
return { user, profile, posts };
} catch (error) {
console.log('异步流程出错:', error.message);
throw error;
}
}
// 模拟异步执行器
function runAsync(generator) {
const gen = generator();
function handle(result) {
if (result.done) {
return result.value;
}
// 模拟异步操作
return Promise.resolve(result.value)
.then(data => {
console.log('异步操作完成:', data);
return handle(gen.next(data));
})
.catch(error => {
console.log('异步操作失败:', error);
return handle(gen.throw(error));
});
}
return handle(gen.next());
}
// 模拟fetch函数
function fetch(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (url.includes('user')) {
resolve({ id: 1, name: '张三' });
} else if (url.includes('profile')) {
resolve({ bio: '前端开发者' });
} else if (url.includes('posts')) {
resolve([{ title: '文章1' }, { title: '文章2' }]);
} else {
reject(new Error('API not found'));
}
}, 100);
});
}
// 执行异步流程
runAsync(asyncFlowControl).then(result => {
console.log('异步流程完成:', result);
}).catch(error => {
console.log('异步流程失败:', error);
});
// 4. 数据流处理
console.log('\n=== 数据流处理 ===');
function* dataProcessor(data) {
console.log('开始处理数据流');
for (const item of data) {
// 数据验证
if (typeof item !== 'number') {
console.log(`跳过无效数据: ${item}`);
continue;
}
// 数据转换
const processed = item * 2;
console.log(`处理: ${item} -> ${processed}`);
// 条件过滤
if (processed > 10) {
yield processed;
}
}
console.log('数据流处理完成');
}
const rawData = [1, 'invalid', 3, 5, 'bad', 7, 2];
const processor = dataProcessor(rawData);
const processedResults = [...processor];
console.log('处理结果:', processedResults);
// 5. 实际应用:分批处理大数据
console.log('\n=== 分批处理大数据 ===');
function* batchProcessor(data, batchSize = 3) {
for (let i = 0; i < data.length; i += batchSize) {
const batch = data.slice(i, i + batchSize);
console.log(`处理批次 ${Math.floor(i / batchSize) + 1}:`, batch);
// 模拟批处理操作
const processedBatch = batch.map(item => ({
original: item,
processed: item.toUpperCase(),
timestamp: new Date().toISOString()
}));
yield processedBatch;
// 可以在这里添加延迟,避免过载
console.log('批次处理完成,准备下一批...');
}
}
const largeDataset = [
'apple', 'banana', 'cherry', 'date', 'elderberry',
'fig', 'grape', 'honeydew', 'kiwi', 'lemon'
];
console.log('大数据分批处理:');
for (const batch of batchProcessor(largeDataset, 3)) {
console.log('批处理结果:', batch);
// 在实际应用中,这里可以将批处理结果发送到服务器
}通过本节ES6迭代器和生成器教程的学习,你已经掌握:
A: Generator函数可以暂停和恢复执行,返回Generator对象而不是直接返回值。它们使用function*语法定义,内部可以使用yield关键字。
A: 当处理大量数据、需要惰性求值、或者数据是动态生成时,Iterator更合适。它们不需要一次性加载所有数据到内存中。
A: Generator可以实现类似async/await的异步控制,但async/await更简洁直观。Generator更适合复杂的流程控制和数据流处理。
A: yield返回单个值,yield委托给另一个可迭代对象,会逐个yield该对象的所有值。yield相当于在循环中对每个值执行yield。
A: Generator的性能很好,特别是在处理大数据集时。由于惰性求值的特性,它们通常比预先计算所有值的方法更节省内存。
"掌握迭代器和生成器是理解现代JavaScript高级特性的重要里程碑。它们不仅提供了优雅的数据遍历方式,还为异步编程和复杂流程控制开辟了新的可能性。在实际开发中灵活运用这些特性,让你的代码更高效、更优雅!"