Iterator 迭代器与 Generator 生成器

理解 JavaScript 迭代器协议和生成器函数的使用

问题

解释 Iterator 迭代器和 Generator 生成器的概念,以及它们的关系和使用场景。

解答

Iterator 迭代器

迭代器是一个对象,它实现了 next() 方法,每次调用返回 {value, done} 结构。

// 手动实现一个迭代器
function createIterator(arr) {
  let index = 0;
  return {
    next() {
      if (index < arr.length) {
        return { value: arr[index++], done: false };
      }
      return { value: undefined, done: true };
    }
  };
}

const iterator = createIterator([1, 2, 3]);
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 }

可迭代对象

实现 [Symbol.iterator] 方法的对象可以被 for...of 遍历。

// 创建可迭代对象
const range = {
  start: 1,
  end: 5,
  
  // 实现迭代器接口
  [Symbol.iterator]() {
    let current = this.start;
    const end = this.end;
    
    return {
      next() {
        if (current <= end) {
          return { value: current++, done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};

// 可以使用 for...of
for (const num of range) {
  console.log(num); // 1, 2, 3, 4, 5
}

// 可以使用展开运算符
console.log([...range]); // [1, 2, 3, 4, 5]

Generator 生成器

生成器函数使用 function* 声明,通过 yield 暂停执行,自动实现迭代器协议。

// 生成器函数
function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = numberGenerator();
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 num of numberGenerator()) {
  console.log(num); // 1, 2, 3
}

用生成器简化可迭代对象

// 使用生成器重写 range
const range = {
  start: 1,
  end: 5,
  
  *[Symbol.iterator]() {
    for (let i = this.start; i <= this.end; i++) {
      yield i;
    }
  }
};

console.log([...range]); // [1, 2, 3, 4, 5]

生成器的双向通信

function* conversation() {
  const name = yield '你叫什么名字?';
  const hobby = yield `${name},你的爱好是什么?`;
  return `${name} 喜欢 ${hobby}`;
}

const talk = conversation();
console.log(talk.next().value);        // '你叫什么名字?'
console.log(talk.next('小明').value);  // '小明,你的爱好是什么?'
console.log(talk.next('编程').value);  // '小明 喜欢 编程'

实际应用:异步流程控制

// 模拟异步操作
function fetchUser() {
  return new Promise(resolve => 
    setTimeout(() => resolve({ name: '张三' }), 100)
  );
}

function fetchPosts(name) {
  return new Promise(resolve => 
    setTimeout(() => resolve([`${name}的文章1`, `${name}的文章2`]), 100)
  );
}

// 生成器 + 执行器实现类似 async/await
function* fetchData() {
  const user = yield fetchUser();
  const posts = yield fetchPosts(user.name);
  return posts;
}

// 简单的执行器
function run(generator) {
  const gen = generator();
  
  function step(value) {
    const result = gen.next(value);
    if (result.done) {
      return Promise.resolve(result.value);
    }
    return Promise.resolve(result.value).then(step);
  }
  
  return step();
}

run(fetchData).then(posts => {
  console.log(posts); // ['张三的文章1', '张三的文章2']
});

关键点

  • 迭代器协议:实现 next() 方法,返回 {value, done} 对象
  • 可迭代协议:实现 [Symbol.iterator] 方法,返回迭代器,支持 for...of 和展开运算符
  • 生成器函数function* 声明,yield 暂停,自动实现迭代器协议
  • 双向通信next(value) 可以向生成器内部传值
  • async/await 原理:生成器 + Promise 执行器是 async/await 的实现基础