author: 专注前端开发,分享JavaScript干货
title: JavaScript进阶①|迭代器与生成器,手写可迭代对象
update: 2026-04-28
tags: JavaScript,迭代器,生成器,Iterator,Generator,Symbol.iterator,前端进阶

作者:专注前端开发,分享JavaScript干货
更新时间:2026年4月
适合人群:掌握ES6基础,想深入理解迭代机制的开发者


前言:迭代器是什么?

迭代器(Iterator) 是一种接口,定义了如何遍历一个对象。

生成器(Generator) 是创建迭代器的特殊函数,用 function*yield 实现。


一、可迭代对象(Iterable)

// 可迭代对象:实现了 [Symbol.iterator] 方法的对象
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();

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()); // { value: undefined, done: true }

// 内置可迭代对象
console.log(arr[Symbol.iterator]);          // Function
console.log("hello"[Symbol.iterator]);     // Function
console.log(new Set()[Symbol.iterator]);    // Function
console.log(new Map()[Symbol.iterator]);    // Function

// 普通对象默认不可迭代
const obj = { a: 1, b: 2 };
// console.log(obj[Symbol.iterator]); // undefined ❌

二、手写可迭代对象

// 让对象变成可迭代的
const myObj = {
    data: [10, 20, 30],
    
    // 实现 [Symbol.iterator] 方法
    [Symbol.iterator]() {
        let index = 0;
        const data = this.data;
        
        return {
            next() {
                if (index < data.length) {
                    return { value: data[index++], done: false };
                } else {
                    return { value: undefined, done: true };
                }
            }
        };
    }
};

// 现在可以用 for...of 遍历了
for (const item of myObj) {
    console.log(item); // 10, 20, 30
}

// 也可以用 spread 操作符
console.log([...myObj]); // [10, 20, 30]

三、生成器(Generator)基础

// 生成器函数:function* 定义
function* myGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

// 调用生成器函数,返回迭代器
const gen = myGenerator();

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 }

// 生成器是可迭代的(实现了 [Symbol.iterator])
for (const value of myGenerator()) {
    console.log(value); // 1, 2, 3
}

四、生成器的高级用法

4.1 yield 传值

function* gen() {
    const x = yield 10;      // 第一个 next() 返回 10
    console.log("x =", x);   // x = 20(第二个 next 传入的值)
    const y = yield x * 2;  // 第二个 next 返回 20*2=40
    console.log("y =", y);   // y = 30
    return x + y;            // 最终返回值
}

const g = gen();
console.log(g.next());       // { value: 10, done: false }
console.log(g.next(20));     // x 被赋值为 20,返回 { value: 40, done: false }
console.log(g.next(30));     // y 被赋值为 30,返回 { value: 50, done: true }

4.2 yield* 委托

function* inner() {
    yield "a";
    yield "b";
    return "inner done";
}

function* outer() {
    yield "开始";
    const result = yield* inner(); // 委托给 inner,接收其 return 值
    console.log(result);          // "inner done"
    yield "结束";
}

for (const v of outer()) {
    console.log(v); // "开始", "a", "b", "结束"
}

4.3 生成器实现异步(早期的 async/await)

// 用生成器模拟 async/await
function* fetchData() {
    const user = yield fetch("https://jsonplaceholder.typicode.com/users/1");
    console.log("用户:", user);
    const posts = yield fetch("https://jsonplaceholder.typicode.com/posts?userId=1");
    console.log("帖子:", posts);
    return { user, posts };
}

// 运行生成器的辅助函数
function runGenerator(gen) {
    const iterator = gen();
    
    function handle(result) {
        if (result.done) return result.value;
        
        // 假设 yield 后面跟的是 Promise
        return result.value.then(data => {
            return handle(iterator.next(data));
        });
    }
    
    return handle(iterator.next());
}

runGenerator(fetchData);

五、实战:自定义范围迭代器

// 创建一个可迭代的范围对象
function createRange(start, end, step = 1) {
    return {
        [Symbol.iterator]() {
            let current = start;
            
            return {
                next() {
                    if ((step > 0 && current < end) || (step < 0 && current > end)) {
                        const value = current;
                        current += step;
                        return { value, done: false };
                    } else {
                        return { value: undefined, done: true };
                    }
                }
            };
        }
    };
}

// 使用
for (const num of createRange(0, 10, 2)) {
    console.log(num); // 0, 2, 4, 6, 8
}

console.log([...createRange(5, 0, -1)]); // [5, 4, 3, 2, 1]

六、实战:异步任务队列(Generator版)

// 用生成器实现异步任务队列
function* taskQueue() {
    console.log("任务1开始");
    yield new Promise(resolve => setTimeout(() => {
        console.log("任务1完成");
        resolve();
    }, 1000));
    
    console.log("任务2开始");
    yield new Promise(resolve => setTimeout(() => {
        console.log("任务2完成");
        resolve();
    }, 1000));
    
    console.log("任务3开始");
    yield new Promise(resolve => setTimeout(() => {
        console.log("任务3完成");
        resolve();
    }, 1000));
    
    return "所有任务完成";
}

// 运行队列
function runQueue(gen) {
    const it = gen();
    
    function iterate(iteration) {
        if (iteration.done) {
            console.log(iteration.value);
            return;
        }
        
        const promise = iteration.value;
        promise.then(() => {
            iterate(it.next());
        });
    }
    
    iterate(it.next());
}

runQueue(taskQueue);
// 输出:任务1开始 → 任务1完成 → 任务2开始 → 任务2完成 → ...

七、知识卡

概念 说明
Symbol.iterator 使对象可迭代
next() 返回 { value, done }
function* 定义生成器函数
yield 暂停并返回值
yield* 委托给另一个可迭代对象
for...of 遍历可迭代对象
... 展开可迭代对象

八、课后作业

  1. 手写一个 range(1, 10) 可迭代对象,用 for...of 遍历输出 1-10
  2. 用生成器实现一个斐波那契数列生成器,调用 next() 依次返回 0, 1, 1, 2, 3, 5…
  3. 实现一个 take(gen, n) 函数,从生成器中取前 n 个值

有问题欢迎评论区留言,大家一起讨论!


标签:JavaScript | 迭代器 | 生成器 | Iterator | Generator | Symbol.iterator | 前端进阶

更多推荐