JavaScript教程:深入理解生成器(Generators)

JavaScript教程:深入理解生成器(Generators)

ru.javascript.info Современный учебник JavaScript ru.javascript.info 项目地址: https://gitcode.com/gh_mirrors/ru/ru.javascript.info

什么是生成器?

在JavaScript中,普通函数只能返回单个值(或不返回任何值)。而生成器(Generators)则完全不同,它们可以按需逐个"产出"(yield)多个值。生成器与可迭代对象配合得天衣无缝,能轻松创建数据流。

生成器函数基础

生成器函数使用特殊的语法结构function*来声明:

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}

调用生成器函数时,它不会立即执行函数体内的代码,而是返回一个称为"生成器对象"的特殊对象,用于控制执行流程。

let generator = generateSequence();
console.log(generator); // [object Generator]

生成器工作原理

生成器对象的主要方法是next()。调用它会执行代码直到最近的yield语句,然后暂停执行并返回一个包含两个属性的对象:

  • value: yield产出的值
  • done: 如果函数执行完毕则为true,否则为false
let one = generator.next();
console.log(one); // {value: 1, done: false}

每次调用next()都会恢复执行,直到下一个yieldreturn

let two = generator.next(); // {value: 2, done: false}
let three = generator.next(); // {value: 3, done: true}

生成器与迭代

生成器是可迭代的,这意味着我们可以使用for..of循环来遍历它们:

function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}

for(let value of generateSequence()) {
  console.log(value); // 1, 2, 3
}

注意:for..of会忽略return返回的值,只遍历yield产出的值。

生成器的实际应用

1. 创建可迭代对象

生成器可以简化可迭代对象的创建。例如,创建一个数字范围迭代器:

let range = {
  from: 1,
  to: 5,
  *[Symbol.iterator]() { // 简写形式
    for(let value = this.from; value <= this.to; value++) {
      yield value;
    }
  }
};

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

2. 生成无限序列

生成器可以创建无限序列,这在某些场景下非常有用:

function* generateRandomNumbers() {
  while(true) {
    yield Math.random();
  }
}

3. 生成器组合

使用yield*语法可以将多个生成器组合在一起:

function* generateDigits() {
  yield* [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
}

function* generateAlphabet() {
  // A-Z
  for(let i = 65; i <= 90; i++) yield String.fromCharCode(i);
  // a-z
  for(let i = 97; i <= 122; i++) yield String.fromCharCode(i);
}

function* generatePasswordChars() {
  yield* generateDigits();
  yield* generateAlphabet();
  yield* ['!', '@', '#', '$'];
}

双向通信

生成器真正强大的地方在于它们支持双向通信 - 不仅能产出值,还能接收外部传入的值:

function* gen() {
  let result = yield "2 + 2 = ?"; // 向外传递问题
  console.log(result); // 接收外部传入的值
}

let generator = gen();
let question = generator.next().value; // "2 + 2 = ?"
generator.next(4); // 向生成器传递答案

错误处理

我们可以使用generator.throw()方法向生成器内部抛出错误:

function* gen() {
  try {
    let result = yield "2 + 2 = ?";
    console.log(result);
  } catch(e) {
    console.log("捕获错误:", e);
  }
}

let generator = gen();
generator.next(); // 启动生成器
generator.throw(new Error("答案未找到")); // 抛出错误

生成器的优势

  1. 惰性求值:值只在需要时才计算
  2. 内存高效:不需要预先生成所有值
  3. 无限序列:可以表示无限的数据流
  4. 更清晰的异步代码:与async/await配合使用

总结

生成器是JavaScript中一个强大但常被忽视的特性。它们提供了一种优雅的方式来处理数据流、创建自定义迭代器以及实现复杂的控制流程。虽然在现代JavaScript中不常用,但在处理特定问题时,生成器能提供简洁高效的解决方案。

理解生成器的工作原理和适用场景,将帮助你写出更灵活、更高效的JavaScript代码。

ru.javascript.info Современный учебник JavaScript ru.javascript.info 项目地址: https://gitcode.com/gh_mirrors/ru/ru.javascript.info

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜默业

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值