ES6 Generator函数详解:语法、执行机制与yield特性

作者:拾光

时间:2026-10-23

浏览:293

本文深入解析ES6提供的Generator函数,阐述其作为状态机和遍历器生成函数的双重特性。详细讲解语法特征、分段执行机制、yield与return的区别,以及next方法传参对yield返回值的影响,帮助开发者掌握这一异步编程核心工具。

文章目录

前言

Generator函数概述

Generator函数是ES6规范中引入的一种用于处理异步编程的机制,其语法行为与传统函数存在显著差异。

从多个维度理解Generator函数,首先可以将其视为一个状态机,其中封装了多个内部状态。

执行Generator函数会返回一个遍历器对象,这意味着Generator函数除了充当状态机外,还是一个遍历器对象的生成函数。通过返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。

接下来将详细介绍相关内容。

语法与形式特征

语法层面

从语法角度理解,Generator函数本质上是一个状态机,封装了多个内部状态。执行该函数会返回一个遍历器对象,即它同时具备状态机和遍历器对象生成函数的特性。返回的遍历器对象允许依次访问Generator函数内部的各个状态。

形式特征

Generator函数在形式上是一个普通函数,但具备两个显著特征。

第一,在function关键字与函数名之间必须添加一个星号(*);第二,函数体内部使用yield表达式来定义不同的内部状态(yield在英语中意为“产出”)。

调用机制与执行流程

调用方式

Generator函数的调用方式与普通函数相同,即在函数名后加一对圆括号。不同之处在于,调用Generator函数后,函数体并不会立即执行,而是返回一个指向内部状态的指针对象,即前文提到的遍历器对象(Iterator Object)。必须调用该遍历器对象的next方法,指针才会移向下一个状态。每次调用next方法,内部指针从函数头部或上一次暂停的位置开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator函数的执行是分段的,yield表达式标志着暂停执行,而next方法用于恢复执行。


function* helloWorldGenerator() {
 yield 'hello';
 yield 'world';
 return 'ending';
}

var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

调用Generator函数会返回一个遍历器对象,代表函数内部的指针。此后,每次调用遍历器对象的next方法,都会返回一个包含value和done两个属性的对象。value属性表示当前内部状态的值,即yield表达式后方表达式的值;done属性为布尔值,指示遍历是否结束。

yield表达式详解

yield表达式

yield表达式与return语句既有相似之处,也有区别。相似点在于,两者都能返回紧跟在语句后的表达式的值。区别在于,每次遇到yield,函数会暂停执行,下次从该位置继续向后执行,而return语句不具备位置记忆功能。一个函数中只能执行一次(或一个)return语句,但可以执行多次(或多个)yield表达式。普通函数只能返回一个值,因为只能执行一次return;而Generator函数可以返回一系列值,因为可以有任意多个yield。从另一个角度看,Generator生成了系列值,这也是其名称的由来(英语中generator意为“生成器”)。

语法注意事项:

1. yield表达式只能出现在Generator函数内部。

2. 如果yield表达式用于其他表达式中,必须将其置于圆括号内。

3. 当yield表达式用作函数参数或位于赋值表达式的右侧时,可以不加括号。

例如:


function* demo() {
 foo(yield 'a', yield 'b'); // OK
 let input = yield; // OK
}

next方法传参机制

next方法的参数

yield表达式本身没有返回值(例如let a = yield;会返回undefined),或者说总是返回undefined。next方法可以接受一个参数,该参数将被视为上一个yield表达式的返回值(注意,是表达式的返回值,例如let a = yield...,参数会成为a的值,并覆盖表达式之前的值)。


function* f() {
 for(var i = 0; true; i++) {
 var reset = yield i;
 console.log(reset);
 if(reset) { i = -1; }
 }
}

var g = f();

g.next() 

Generator函数概述

由于next方法的参数表示上一个yield表达式的返回值,因此在第一次调用next方法时,传递参数是无效的。V8引擎会直接忽略第一次调用next方法时的参数,只有从第二次调用next方法开始,参数才有效。从语义上讲,第一个next方法用于启动遍历器对象,因此无需携带参数。

总结

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对本站的支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章