生成器概念理解及使用
使用方法如下:
function* WeaponGenerator() { // 通过在关键字 function 后面添加星号 * 定义生成器函数 yield "Katana"; // 使用新的关键字 yield 生成独立的值 yield "Wakizashi"; yield "Kusarigama"; }(for-of 循环是对迭代器进行迭代的语法糖) 对初学者来说,调用生成器并不会执行生成器函数,相反,它会创建一个叫作迭代器(iterator)的对象: 迭代器用于控制生成器的执行。迭代器对象暴露的最基本接口是 next 方法。这个方法可以用来向生成器请求一个值,从而控制生成器:
for (let weapon of WeaponGenerator()) { assert(weapon !== undefined, weapon); }
const result1 = weaponsIterator.next();next 函数调用后,生成器就开始执行代码,当代码执行到 yield 关键字时,就会生成一个中间结果(生成值序列中的一项),然后返回一个新对象,其中封装了结果值和一个指示完成的指示器。 每当生成一个当前值后,生成器就会非阻塞地挂起执行,随后耐心等待下一次值请求的到达。
把执行权交给下一个生成器
正如在标准函数中调用另一个标准函数,我们需要把生成器的执行委托给另一个生成器。function* WarriorGenerator(){ yield "Sun Tzu"; yield* NinjaGenerator(); // yield*将执行权交给了另一个生成器 yield "Genghis Khan"; } function* NinjaGenerator(){ yield "Hattori"; yield "Yoshi"; } for(let warrior of WarriorGenerator()){ assert(warrior !== null, warrior); // Sun Tzu、Hattori、Yoshi、Genghis Khan }
作为生成器函数参数发送值
function* NinjaGenerator(action) { const imposter = yield ("Hattori " + action); assert(imposter === "Hanzo", "The generator has been infiltrated"); yield ("Yoshi (" + imposter + ") " + action); } const ninjaIterator = NinjaGenerator("skulk"); const result1 = ninjaIterator.next(); assert(result1.value === "Hattori skulk","Hattori is skulking"); const result2 = ninjaIterator.next("Hanzo"); assert(result2.value === "Yoshi (Hanzo) skulk", "We have an imposter!");第二次调用 ninjaIterator 的 next 方法则发生了有趣的事:ninjaIterator.next("Hanzo")。这一次,我们使用 next 方法将计算得到的值又传递回生成器。生成器函数耐心地等待着,在表达式 yield ("Hattori " + action)位置挂起,故而值 Hanzo 作为参数传入了 next()方法,并用作整个 yield 表达式的值。本例中,也就是表示语句 imposter = yield("Hattori " + action) 中的变量 imposter 会以值 Hanzo 作为结尾。