JavaScript生成器,如何定义一个生成器,如何使用yield?
发布于 作者:苏南大叔 来源:程序如此灵动~
本文对nodejs的生成器做个简要的描述,它和python的生成器是存在差别的。所以,完全套用python里yield用法的话,可能会产生误解。本文以苏南大叔对JavaScript里面的生成器的理解为主,如有偏差,欢迎留言。

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0,chrome@131.0.6778.205。yield语句就像是个指针,随着指针的移动,从一个yield走向另外一个yield,最终碰到return。
定义生成器
JavaScript里面的Generator生成器,是很奇怪的。它是通过在函数定义的时候,加个*来表示一个生成器的。
- 没有匿名函数版的生成器,匿名函数不能加
*,必须有function关键字。 async和*,还可以同时作用到一个function关键字上,左右护法。*是靠近左边或者右边或者中间,不重要。但是,格式化函数的时候,就会变成function*。- 生成器的重要标识就是
function关键字后面的这个*,而不是yield。 - 能用
yield就别用return来返回值,虽然两者的功能看起来一致。但是,有些写法里面只认yield,不认return。
function* g0() {
console.log("g0");
}
function * g1() {
console.log("g1");
}
const g2 = function *() {
console.log("g2");
};
const g3 = async function * () {
console.log("g3");
};仅定义不执行
在生成器名字后面加上一个(),并不会执行这个生成器函数。或者说,function*返回值就是函数本身,这也能解释它为啥不执行函数体内的逻辑这个问题。
let a = g0();
let b = g1();
let c = g2();
let d = g3();上述代码执行完后,生成器内部的console.log()并没有被执行。它(们)等待着.next()命令。
a.next();
b.next();
c.next();
d.next();.next()、yield、return
.next()使得生成器逻辑得到继续运行,但是碰到yield就会停止执行。当.next()再次执行的时候,从yield的下一个逻辑开始执行,直到碰到下一个yield逻辑(或者return)为止。【仔细品味这句话,一次一次的想】
yield的作用是:阻碍并返回一个值。
.next()从yield拿到的返回值很奇怪,是个对象。类似:{ value: 1, done: false }。.next()可以无限执行,并不会爆异常,恒定会得到{ value: undefined, done: true }。
function* g0() {
let i = 0;
yield i++;
yield i++;
return i;
}
let a = g0();
console.log(a.next()); // { value: 0, done: false }
console.log(a.next()); // { value: 1, done: false }
console.log(a.next()); // { value: 2, done: true }
console.log(a.next()); // { value: undefined, done: true }
console.log(a.next()); // { value: undefined, done: true }所以,done为true的条件是:确实执行到了末尾。比如:碰到了return,或者}。
function* g0() {
let i = 0;
yield i++;
yield i++;
}
let a = g0();
console.log(a.next()); // { value: 0, done: false }
console.log(a.next()); // { value: 1, done: false }
console.log(a.next()); // { value: undefined, done: true}
console.log(a.next()); // { value: undefined, done: true }.next(外部值) <=> yield 内部值
执行一个生成器,就是外部和内部不断交互的结果。
- 内部可以通过
yield 内部值来使得外部的.next()获得“内部值”。 - 通过
.next(外部值)使得内部的yield左边的表达式获得“外部值”。【这个逻辑很惊为天人】

function* g0() {
let i = 0;
let j = yield i++;
yield j++;
return j;
}
let a = g0();
console.log(a.next(55)); // { value: 0, done: false }
console.log(a.next(66)); // { value: 66, done: false }
console.log(a.next(77)); // { value: 67, done: true }
console.log(a.next(88)); // { value: undefined, done: true }.next(55)的时候,代码从右往左执行到yield的y,就返回了i值0。.next(66)的时候,代码从yield的y从右往左执行,66被带入,实际执行的是let j = 66。