理解迭代器的基本原理。
// 迭代器是一个对象,提供next()方法
const iterator = {
data: [1, 2, 3],
index: 0,
next() {
if (this.index < this.data.length) {
return { value: this.data[this.index++], done: false };
}
return { done: true };
}
};
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 }
// 迭代器协议:实现next()方法
// next()返回 { value: any, done: boolean }
function createIterator(arr) {
let index = 0;
return {
next() {
if (index < arr.length) {
return { value: arr[index++], done: false };
}
return { done: true };
}
};
}
const iter = createIterator([1, 2, 3]);
console.log(iter.next()); // { value: 1, done: false }
console.log(iter.next()); // { value: 2, done: false }
实现可迭代协议的对象。
// 可迭代对象实现Symbol.iterator方法
const iterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
const data = this.data;
return {
next() {
if (index < data.length) {
return { value: data[index++], done: false };
}
return { done: true };
}
};
}
};
// 使用for...of遍历
for (const item of iterable) {
console.log(item); // 1 2 3
}
// 使用展开运算符
console.log([...iterable]); // [1, 2, 3]
// 使用解构
const [a, b, c] = iterable;
console.log(a, b, c); // 1 2 3
// 数组
const arr = [1, 2, 3];
console.log(typeof arr[Symbol.iterator]); // "function"
// 字符串
const str = "东巴文";
console.log(typeof str[Symbol.iterator]); // "function"
// Map
const map = new Map([["a", 1], ["b", 2]]);
console.log(typeof map[Symbol.iterator]); // "function"
// Set
const set = new Set([1, 2, 3]);
console.log(typeof set[Symbol.iterator]); // "function"
// arguments
function foo() {
console.log(typeof arguments[Symbol.iterator]); // "function"
}
foo();
// 自定义范围迭代器
class Range {
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 };
}
return { done: true };
}
};
}
}
const range = new Range(0, 10, 2);
for (const num of range) {
console.log(num); // 0 2 4 6 8
}
完整的迭代器协议。
// return方法在提前退出时调用
const iterable = {
data: [1, 2, 3, 4, 5],
[Symbol.iterator]() {
let index = 0;
const data = this.data;
return {
next() {
if (index < data.length) {
return { value: data[index++], done: false };
}
return { done: true };
},
return(value) {
console.log("迭代器提前退出");
return { value, done: true };
}
};
}
};
// break触发return
for (const item of iterable) {
console.log(item);
if (item === 2) break;
}
// 1
// 2
// 迭代器提前退出
// throw方法(可选)
const iterable2 = {
[Symbol.iterator]() {
return {
next() {
return { value: 1, done: false };
},
throw(error) {
console.log("抛出错误:", error);
return { done: true };
}
};
}
};
使用function*创建生成器。
// 生成器函数
function* generator() {
yield 1;
yield 2;
yield 3;
}
// 创建生成器
const gen = generator();
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 }
// 生成器是可迭代对象
for (const value of generator()) {
console.log(value); // 1 2 3
}
// 生成器函数表达式
const genFunc = function*() {
yield 1;
yield 2;
};
// 对象方法
const obj = {
*generator() {
yield "东巴文";
yield "db-w.cn";
}
};
// 类方法
class MyClass {
*generator() {
yield 1;
yield 2;
}
}
yield的详细用法。
function* generator() {
const a = yield 1;
console.log("a:", a);
const b = yield 2;
console.log("b:", b);
return "结束";
}
const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next("A")); // a: A, { value: 2, done: false }
console.log(gen.next("B")); // b: B, { value: "结束", done: true }
// yield*委托给另一个生成器
function* inner() {
yield 1;
yield 2;
}
function* outer() {
yield "开始";
yield* inner();
yield* [3, 4];
yield "结束";
}
for (const value of outer()) {
console.log(value);
}
// 开始 1 2 3 4 结束
// 递归生成器
function* treeTraversal(node) {
yield node.value;
if (node.left) yield* treeTraversal(node.left);
if (node.right) yield* treeTraversal(node.right);
}
生成器对象的方法。
function* generator() {
const value = yield 1;
return value * 2;
}
const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next(10)); // { value: 20, done: true }
function* generator() {
yield 1;
yield 2;
yield 3;
}
const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.return("结束")); // { value: "结束", done: true }
console.log(gen.next()); // { value: undefined, done: true }
function* generator() {
try {
yield 1;
yield 2;
} catch (error) {
console.log("捕获错误:", error);
yield "恢复";
}
yield 3;
}
const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.throw(new Error("出错了"))); // 捕获错误: Error: 出错了
// { value: "恢复", done: false }
console.log(gen.next()); // { value: 3, done: false }
生成器的实际应用场景。
// 无限序列
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
// 只计算需要的值
function* take(iterable, n) {
let count = 0;
for (const value of iterable) {
if (count++ >= n) break;
yield value;
}
}
for (const num of take(fibonacci(), 10)) {
console.log(num); // 1 1 2 3 5 8 13 21 34 55
}
// 使用生成器处理异步
function* fetchUser() {
const user = yield fetch("/api/user").then(r => r.json());
const posts = yield fetch(`/api/posts/${user.id}`).then(r => r.json());
return { user, posts };
}
function runGenerator(gen) {
const iterator = gen();
function handle(result) {
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value)
.then(data => handle(iterator.next(data)))
.catch(error => handle(iterator.throw(error)));
}
return handle(iterator.next());
}
runGenerator(fetchUser).then(result => {
console.log(result);
});
// 使用生成器实现状态机
function* stateMachine() {
while (true) {
yield "idle";
yield "running";
yield "paused";
}
}
const machine = stateMachine();
console.log(machine.next().value); // "idle"
console.log(machine.next().value); // "running"
console.log(machine.next().value); // "paused"
console.log(machine.next().value); // "idle"
// 生成器管道
function* map(iterable, fn) {
for (const value of iterable) {
yield fn(value);
}
}
function* filter(iterable, fn) {
for (const value of iterable) {
if (fn(value)) yield value;
}
}
function* take(iterable, n) {
let count = 0;
for (const value of iterable) {
if (count++ >= n) break;
yield value;
}
}
// 使用
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const pipeline = take(
filter(
map(numbers, x => x * 2),
x => x > 5
),
3
);
console.log([...pipeline]); // [6, 8, 10]
掌握了迭代器与生成器后,让我们继续学习:
东巴文(db-w.cn) - 让编程学习更简单
🎯 东巴文寄语:迭代器和生成器是JavaScript中强大的抽象工具,可以实现惰性计算、数据流处理和异步流程控制。在 db-w.cn,我们帮你深入理解这些高级概念!