编程 js生成器函数

2024-11-18 15:21:08 +0800 CST views 735

生成器函数(一)

生成器初识

生成器函数使用 function* 语法,返回一个生成器(迭代器),允许定义一个非连续执行的函数作为迭代算法。

生成器初次调用时,不会执行代码,而是返回一个生成器对象。通过调用 next() 方法逐步执行,直到遇到 yield 关键字为止。每次调用都返回一个生成器对象(每个生成器只能迭代一次)。

以下是通过生成器编写的简单迭代器示例:

function* testIterator(start = 1, end = 5) {
  let count = start;
  for (let value = start; value < end; value++) {
    count++;
    yield value;
  }
  return count;
}
const customItertor = testIterator();
for (const index of Array(7)) {
  console.log(customItertor.next());
}

在此例中,生成器按 yield 的顺序逐步执行,返回每次的值。for 循环调用 next(),每次执行到 yield 后停止,直到完成全部迭代。


生成器函数(二)

生成器函数调用时会产生一个生成器对象,通过调用 next() 方法逐步执行。因为生成器对象是特殊的迭代器,它实现了 Iterator 接口。本文将进一步讲述生成器的用法。

目录

  1. 返回值是什么
  2. 如何传参
  3. 如何提前结束
  4. 委托执行
  5. 场景示例一:将原生对象改造为可迭代对象
  6. 场景示例二:遍历自定义类的键值
  7. 下节预告

返回值是什么

生成器是特殊的迭代器,按 yield 逐步执行,返回的值格式与迭代器相同。valueyield 后的表达式值,直到遇到 return。当 donetrue 后,后续的 yield 不会再执行,调用 next() 时返回 { value: undefined, done: true }

function* customGenerator() {
  console.log('开始执行');
  yield 'a';
  let count = 0;
  yield count + 2;
  return 'b';
  yield count;
}

console.log('第一次调用');
const testGenerator = customGenerator();

console.log('开始调用next()方法');
for (const index of Array(4)) {
  console.log(testGenerator.next());
}

初次调用生成器时,返回生成器对象,只有调用 next() 后,生成器才开始逐步执行。


如何传参

在生成器的每步执行中,可以通过 next() 方法传递参数,并赋值给 yield 左侧的变量。这意味着在每次调用 next() 时,会从上一个 yield 处继续执行。

function* customGenerator() {
  const value1 = yield 'a';
  console.log('value1:', value1);
  let count = 0;
  const value2 = yield count + 2;
  console.log('value2:', value2);
  return 'b';
}

const testGenerator = customGenerator();
for (const index in Array.from({ length: 4 })) {
  const count = +index + 1;
  console.log(`第${count}次调用next方法:`);
  console.log(testGenerator.next(count));
}

第一次调用 next() 通常不传参。如果需要传参,可以在创建生成器时传入:

function* customGenerator(value0) {
  console.log('value0:', value0);
  const value1 = yield 'a';
  console.log('value1:', value1);
  let count = 0;
  const value2 = yield count + 2;
  console.log('value2:', value2);
  return 'b';
}

const testGenerator = customGenerator('第一个参数');
for (const index in Array.from({ length: 2 })) {
  const count = +index + 1;
  console.log(`第${count}次调用next方法:`);
  console.log(testGenerator.next(count));
}

如何提前结束

return

通过 return() 方法,可以提前结束生成器。done 变为 true,并返回 return() 传入的值。

function* customGenerator() {
  const value1 = yield 'a';
  console.log('value1:', value1);
  const value2 = yield 'b';
  console.log('value2:', value2);
  return 'c';
}

const testGenerator = customGenerator();
for (const index in Array.from({ length: 4 })) {
  const count = +index + 1;
  console.log(`第${count}次调用:`);
  if (count === 2) {
    console.log(testGenerator.return(count));
  } else {
    console.log(testGenerator.next(count));
  }
}

throw

也可以通过 throw() 方法向生成器抛出异常,从而提前结束生成器。

function* customGenerator() {
  try {
    const value1 = yield 'a';
    console.log('value1:', value1);
    const value2 = yield 'b';
    console.log('value2:', value2);
    return 'c';
  } catch (error) {
    console.log('捕获到异常:', error.message);
  }
}

const testGenerator = customGenerator();
for (const index in Array.from({ length: 4 })) {
  const count = +index + 1;
  console.log(`第${count}次调用:`);
  if (count === 2) {
    console.log(testGenerator.throw(new Error(`第${count}次调用异常`)));
  } else {
    console.log(testGenerator.next(count));
  }
}

委托执行

生成器函数可以通过 yield* 将执行委托给另一个生成器函数:

function* generatorA() {
  yield 'x';
  yield 'y';
  yield 'z';
}

function* customGenerator() {
  yield 'a';
  yield 'b';
  yield* generatorA();
  yield 'c';
  return '完成';
}

const testGenerator = customGenerator();
for (const index in Array.from({ length: 7 })) {
  const count = +index + 1;
  console.log(`第${count}次调用:`, testGenerator.next());
}

场景示例一:将原生对象改造为可迭代对象

通过生成器可以轻松将对象改造为可迭代对象:

const obj = {
  key1: 'value-1',
  key2: 'value-2',
  key3: 'value-3',
  [Symbol.iterator]: function*() {
    for (const key of Object.keys(this)) {
      yield this[key];
    }
  }
};

for (const value of obj) {
  console.log('value:', value);
}

场景示例二:遍历自定义类的键值

class customClass {
  constructor(value1, value2, value3) {
    this.key1 = value1;
    this.key2 = value2;
    this.key3 = value3;
  }

  *[Symbol.iterator]() {
    yield* Object.entries(this);
  }
}

const testClass = new customClass('value-1', 'value-2', 'value-3');
for (const value of testClass) {
  console.log(`${value[0]}:${value[1]}`);
}

images

推荐文章

html文本加载动画
2024-11-19 06:24:21 +0800 CST
资源文档库
2024-12-07 20:42:49 +0800 CST
JavaScript数组 splice
2024-11-18 20:46:19 +0800 CST
黑客帝国代码雨效果
2024-11-19 01:49:31 +0800 CST
PHP设计模式:单例模式
2024-11-18 18:31:43 +0800 CST
用 Rust 玩转 Google Sheets API
2024-11-19 02:36:20 +0800 CST
禁止调试前端页面代码
2024-11-19 02:17:33 +0800 CST
如何使用go-redis库与Redis数据库
2024-11-17 04:52:02 +0800 CST
使用 node-ssh 实现自动化部署
2024-11-18 20:06:21 +0800 CST
百度开源压测工具 dperf
2024-11-18 16:50:58 +0800 CST
Nginx 状态监控与日志分析
2024-11-19 09:36:18 +0800 CST
前端项目中图片的使用规范
2024-11-19 09:30:04 +0800 CST
php strpos查找字符串性能对比
2024-11-19 08:15:16 +0800 CST
Linux 常用进程命令介绍
2024-11-19 05:06:44 +0800 CST
Nginx 性能优化有这篇就够了!
2024-11-19 01:57:41 +0800 CST
初学者的 Rust Web 开发指南
2024-11-18 10:51:35 +0800 CST
Vue3中如何实现插件?
2024-11-18 04:27:04 +0800 CST
一些好玩且实用的开源AI工具
2024-11-19 09:31:57 +0800 CST
Python 微软邮箱 OAuth2 认证 Demo
2024-11-20 15:42:09 +0800 CST
程序员茄子在线接单