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
。
相关文章
如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。