ES6 Generator 生成器函数详解:语法、next参数与遍历
本文深入解析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程序设计有所帮助。
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
