Skip to content

生成器与迭代器

题目1: 生成器函数的语法是什么?如何使用 yield

答案: 生成器函数使用 function* 语法定义,使用 yield 关键字产生值:

javascript
function* numberGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

const gen = numberGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3

扩展: yield 可以接收值,这个值会作为上一次 next() 调用的返回值。

题目2: 什么是迭代器?如何手动实现一个迭代器?

答案: 迭代器是一个对象,它定义了一个 next() 方法,该方法返回一个包含 valuedone 属性的对象。

手动实现迭代器:

javascript
function createIterator(array) {
    let index = 0;
    return {
        next: function() {
            if (index < array.length) {
                return { value: array[index++], done: false };
            } else {
                return { done: true };
            }
        }
    };
}

const it = createIterator([1, 2, 3]);
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { done: true }

扩展: ES6 引入了 Symbol.iterator,允许对象定义它们的迭代行为。

题目3: 如何使用生成器函数实现异步操作?

答案: 生成器函数可以用于实现异步操作,通常与 Promise 结合使用:

javascript
function* asyncGenerator() {
    const result1 = yield fetch('https://api.example.com/data1');
    console.log(result1);
    const result2 = yield fetch('https://api.example.com/data2');
    console.log(result2);
}

function run(generator) {
    const iterator = generator();
    function iterate(iteration) {
        if (iteration.done) return Promise.resolve(iteration.value);
        return Promise.resolve(iteration.value)
            .then(x => iterate(iterator.next(x)));
    }
    return iterate(iterator.next());
}

run(asyncGenerator);

扩展: 这种模式是 async/await 的前身,现在通常直接使用 async/await。

题目4: 什么是可迭代对象?如何创建一个可迭代对象?

答案: 可迭代对象是实现了 Symbol.iterator 方法的对象。创建可迭代对象:

javascript
const iterableObject = {
    [Symbol.iterator]: function* () {
        yield 1;
        yield 2;
        yield 3;
    }
};

for (const item of iterableObject) {
    console.log(item); // 1, 2, 3
}

扩展: 数组、字符串、Map 和 Set 都是内置的可迭代对象。

题目5: 生成器函数和普通函数的区别是什么?

答案: 主要区别:

  1. 语法:生成器函数使用 function* 声明
  2. 执行:生成器函数返回一个生成器对象,而不是直接执行函数体
  3. 暂停和恢复:生成器函数可以使用 yield 暂停执行,并在之后恢复
  4. 状态保持:生成器函数可以在多次调用之间保持其内部状态
  5. 双向通信:可以通过 next() 方法向生成器传值,通过 yield 从生成器获取值

扩展: 生成器函数特别适合于处理大量数据或无限序列,因为它们可以按需生成值,而不需要一次性将所有值存储在内存中。