ES6 Generator 生成器函数详解:语法、next参数与遍历

作者:代码拾荒时间:2026-10-22 03:18:31浏览:157

本文深入解析ES6 Generator生成器函数,介绍其作为状态遍历器的基本概念与语法。详细讲解next()方法的执行流程、带参数注入值的机制,以及for-of循环与yield*语句在嵌套遍历中的应用,帮助开发者掌握异步编程的核心工具。

本文详细介绍ES6引入的Generator(生成器)函数特性,旨在帮助读者深入理解并应用这一重要语法。

Generator 简介与执行流程

1. 简介

① 核心概念:生成器可被视为一种内部状态的遍历器。每次调用时,函数内部状态发生一次改变。

② 定义语法:


function* f() {}

③ 主要作用:完全控制函数内部状态的变化,并依次遍历这些状态。

④ 执行流程:调用Generator函数时,函数体并不立即执行,而是返回一个遍历器对象(相当于暂停执行)。通过调用next()方法开始执行,遇到yield语句时暂停,返回一个包含value(当前yield的值)和done(false)属性的对象。持续调用next()直到遇到return语句(若无return则执行至函数结束)。next方法返回的对象中,value属性为紧跟在return语句后的表达式值(若无return则为undefined),done属性为true表示遍历结束。

示例:


function* helloWorldGenerator() {
 yield 'hello';
 yield 'world';
 return 'ending';
}
var hw = helloWorldGenerator();//第一次调用该方法不会执行,仅返回一个遍历器。
var a = hw.next();
while(!a.done){ //当执行到return 时,a.done=true,终止循环
 console.log(a.value+','+a.done);
 a = hw.next();
}
console.log(a.value+','+a.done);

结果:


hello,false
world,false
ending,true

next() 方法的参数传递

2. next() 方法的参数传递

① 注意:next()返回的是一个对象,yield语句本身没有返回值(或视为undefined)。next方法可以接收一个参数,该参数将作为上一个yield语句的返回值。


function* f() {
 for(var i=0; true; i++) {
  var reset = yield i;
  console.log(reset); //打印reset,验证yield语句是没有返回值的
  if(reset) { i = -1; }
 }
}
var g = f();
console.log(g.next()) // { value: 0, done: false }
console.log(g.next())// { value: 1, done: false }
console.log(g.next(true)) // { value: 0, done: false }

结果:


{ value: 0, done: false }
undefined
{ value: 1, done: false }
true
{ value: 0, done: false }

通过next方法的参数,可以在Generator函数运行期间,从外部向内部注入值。这意味着可以在不同阶段向函数内部注入不同值,从而动态调整函数行为。

② 由于next方法的参数表示上一个yield语句的返回值,因此第一次调用next方法时不能带有参数。V8引擎会忽略第一次调用next时的参数,只有从第二次调用开始,参数才生效。


function* foo(x) {
 var y = 2 * (yield (x + 1));
 var z = yield (y / 3);
 return (x + y + z);
}
var it = foo(5);
console.log(it.next(3))// { value:6, done:false }
console.log(it.next(12))// { value:8, done:false }
console.log(it.next(13))// { value:42, done:true }

for-of 遍历 Generator

3. 使用 for-of 遍历 Generator

for...of循环可以自动遍历Generator函数,此时无需手动调用next方法。

当next方法返回对象的done属性为true时,for...of循环会立即中止,且不包含该返回对象。


function *foo() {
 yield 1;
 yield 2;
 yield 3;
 yield 4;
 yield 5;
 return 6;
}
for (let v of foo()) {
 console.log(v);
}
// 1 2 3 4 5

yield* 语句与嵌套遍历

4. yield* 语句

① 如果yield命令后跟随的是一个遍历器对象,需要在yield后加上星号(*),表明它返回的是一个遍历器。这被称为yield*语句。


let a = (function* () {
 yield 'Hello!';
 yield 'Bye!';
}());
let b = (function* () {
 yield 'Greetings!';
 yield* a;
 yield 'Ok, bye.';
}());
for(let value of b) {
 console.log(value);
}

结果:


Greetings!
Hello!
Bye!
Ok, bye.

② 若yield命令后不加星号,返回的是整个数组;加上星号则表示返回该数组的遍历器。


function* gen(){
 yield* ["a", "b", "c"];
}
gen().next() // { value:"a", done:false }

遍历嵌套数组示例:


function* iterTree(tree) {
 if (Array.isArray(tree)) {
 for(let i=0; i < tree.length; i++) {
  yield* iterTree(tree[i]);
 }
 } else {
 yield tree;
 }
}
const tree = [ 'a', ['b', 'c'], ['d', 'e'] ];
for(let x of iterTree(tree)) {
 console.log(x);
}// a b c d e

希望本文所述内容对大家学习ECMAScript程序设计有所帮助。

作者最新文章