迭代器
可迭代对象的定义
-
实现
[Symbol.iterator]方法:该方法必须返回一个迭代器对象。 -
迭代器对象 :必须有一个
next()方法,该方法返回一个对象,包含:value:当前迭代的值,可以是任意类型。done:布尔值,表示迭代是否已经结束。
示例
下面是一个简单的可迭代对象示例:
javascript
javascript
const myIterable = {
[Symbol.iterator]: function() {
let count = 0;
return {
next: function() {
if (count < 3) {
count++;
return { value: count, done: false };
}
return { value: undefined, done: true };
}
};
}
};
// 使用 for...of 循环遍历
for (const value of myIterable) {
console.log(value); // 输出 1, 2, 3
}
内置可迭代对象
JavaScript中许多内置对象是可迭代的,例如:
ArrayStringMapSetarguments对象NodeList等DOM集合
可迭代对象的用途
- 用于
for...of循环:可以直接遍历可迭代对象。 - 展开语法(Spread syntax) :例如
[...array]。 - 解构赋值(Destructuring assignment) :例如
let [a, b] = iterable。 Array.from():可以将可迭代对象转换为数组。Promise.all()和Promise.race()等接受可迭代对象的方法。Map和Set的构造函数。
和生成器关系
生成器是迭代器语法糖;生成器函数返回的对象即是一个生成器,也是一个迭代器,因为他实现了迭代器协议
生成器
核心定义
生成器(Generator) 是 ES6 引入的一种特殊函数,它可以通过 yield 关键字暂停和恢复 函数的执行。生成器函数返回一个生成器对象 ,这个对象同时符合可迭代协议 和迭代器协议。
语法特征
javascript
javascript
// 生成器函数的定义
function* generatorFunction() {
// 函数体
yield 'value1';
yield 'value2';
return 'final value';
}
// 或者使用函数表达式
const generator = function* () {
yield 'value';
};
生成器的基本使用
创建和执行生成器
javascript
lua
// 1. 定义生成器函数
function* simpleGenerator() {
console.log('开始执行');
yield '第一个值';
console.log('恢复执行');
yield '第二个值';
console.log('结束执行');
return '最终返回值';
}
// 2. 创建生成器对象
const gen = simpleGenerator();
console.log('生成器创建完成,但尚未执行');
// 3. 执行生成器
console.log(gen.next());
// 输出: "开始执行"
// 输出: { value: '第一个值', done: false }
console.log(gen.next());
// 输出: "恢复执行"
// 输出: { value: '第二个值', done: false }
console.log(gen.next());
// 输出: "结束执行"
// 输出: { value: '最终返回值', done: true }
console.log(gen.next());
// 输出: { value: undefined, done: true }
yield 关键字详解
javascript
lua
function* yieldExamples() {
// 1. 基本 yield
yield '普通值';
// 2. yield 表达式
const result = yield '表达式结果';
console.log('从外部传入的值:', result);
// 3. yield 复杂表达式
yield 2 + 3 * 4; // 14
// 4. yield 函数调用
yield Math.random();
return '完成';
}
const exampleGen = yieldExamples();
console.log(exampleGen.next()); // { value: '普通值', done: false }
console.log(exampleGen.next()); // { value: '表达式结果', done: false }
console.log(exampleGen.next('外部传入的值')); // 从外部传入的值: 外部传入的值
// { value: 14, done: false }
console.log(exampleGen.next()); // { value: 0.123..., done: false }
console.log(exampleGen.next()); // { value: '完成', done: true }
生成器的核心特性
1. 暂停和恢复执行
javascript
javascript
function* pauseResumeDemo() {
console.log('阶段 1');
yield '暂停点 1';
console.log('阶段 2');
yield '暂停点 2';
console.log('阶段 3');
// 可以在循环中使用 yield
for (let i = 0; i < 3; i++) {
console.log(`循环第 ${i + 1} 次`);
yield `循环值 ${i}`;
}
return '全部完成';
}
const demo = pauseResumeDemo();
// 分步执行,完全控制执行流程
let result = demo.next(); // "阶段 1"
console.log('手动处理其他任务...');
setTimeout(() => {
result = demo.next(); // "阶段 2"
console.log('继续其他任务...');
setTimeout(() => {
// 一次性执行剩余部分
while (!result.done) {
result = demo.next();
console.log(result);
}
}, 1000);
}, 1000);
2. 双向通信
javascript
javascript
function* twoWayCommunication() {
console.log('生成器启动');
// 第一次暂停,等待外部输入名字
const name = yield '请问你的名字?';
console.log(`收到名字: ${name}`);
// 第二次暂停,等待外部输入年龄
const age = yield `你好 ${name},请问你的年龄?`;
console.log(`收到年龄: ${age}`);
// 根据年龄判断
if (age < 18) {
return `${name},你还未成年`;
} else {
return `${name},你已经成年了`;
}
}
// 使用生成器进行对话
const conversation = twoWayCommunication();
// 启动对话
let response = conversation.next();
console.log('系统:', response.value); // "请问你的名字?"
// 用户输入名字
response = conversation.next('Alice');
console.log('系统:', response.value); // "你好 Alice,请问你的年龄?"
// 用户输入年龄
response = conversation.next(25);
console.log('系统:', response.value); // "Alice,你已经成年了"
3. 错误处理
javascript
javascript
function* errorHandlingGenerator() {
try {
console.log('开始执行');
yield '第一步';
// 这里可能会抛出错误
const riskyValue = yield '进行危险操作';
if (riskyValue === 'error') {
throw new Error('手动触发的错误');
}
yield `成功: ${riskyValue}`;
return '完成';
} catch (error) {
console.log('捕获到错误:', error.message);
yield `错误处理: ${error.message}`;
return '错误恢复完成';
}
}
const errorGen = errorHandlingGenerator();
// 正常流程
console.log(errorGen.next()); // { value: '第一步', done: false }
console.log(errorGen.next('safe')); // { value: '成功: safe', done: false }
console.log(errorGen.next()); // { value: '完成', done: true }
// 错误流程
const errorGen2 = errorHandlingGenerator();
console.log(errorGen2.next()); // { value: '第一步', done: false }
// 从外部抛出错误到生成器内部
console.log(errorGen2.throw(new Error('外部错误')));
// 输出: "捕获到错误: 外部错误"
// 返回: { value: '错误处理: 外部错误', done: false }
console.log(errorGen2.next()); // { value: '错误恢复完成', done: true }
4、状态机
js
function* trafficLight() {
const states = ['红色', '黄色', '绿色'];
let index = 0;
while (true) {
const command = yield states[index];
if (command === 'next') {
index = (index + 1) % states.length;
} else if (command === 'reset') {
index = 0;
}
}
}
// 使用交通灯状态机
const light = trafficLight();
console.log(light.next().value); // '红色'
console.log(light.next('next').value); // '黄色'
console.log(light.next('next').value); // '绿色'
console.log(light.next('next').value); // '红色'
console.log(light.next('reset').value); // '红色'