迭代器与生成器

迭代器概念

理解迭代器的基本原理。

什么是迭代器

// 迭代器是一个对象,提供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方法

// 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表达式

yield的详细用法。

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*

// 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);
}

生成器方法

生成器对象的方法。

next方法

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 }

return方法

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 }

throw方法

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]

下一步

掌握了迭代器与生成器后,让我们继续学习:

  1. Proxy与Reflect - 学习元编程
  2. Map与Set - 学习集合类型
  3. 模块化概述 - 学习模块化开发

东巴文(db-w.cn) - 让编程学习更简单

🎯 东巴文寄语:迭代器和生成器是JavaScript中强大的抽象工具,可以实现惰性计算、数据流处理和异步流程控制。在 db-w.cn,我们帮你深入理解这些高级概念!