什么是generator函数?
如何创建一个generator函数,代码如下:
function* generator() { yield 1; yield '宋远溪'; yield {name:'宋远溪'} }
generator函数如何使用?继续往下:
function* generator() { yield 1; yield '宋远溪'; yield {name:'宋远溪'} } const genFn = generator(); console.log( genFn.next(), genFn.next(), genFn.next() ) //{ value: 1, done: false } { value: '宋远溪', done: false } { value: { name: '宋远溪' }, done: false }
由代码可以观察到,与普通函数不同的是generator函数调用会返回一个生成器对象,通过调用生成器对象的next(),可以返回generator函数体中的yield的值;
并且,通过调用next()我们可以观察到,生成器对象时可迭代的!
yield 与 next 如何交互?继续往下:
function* generator() { var name = yield "你叫什么名字?"; yield `你好${name}`; } var iterable = generator(); console.log( iterable.next().value, iterable.next('李焕英').value ) //你叫什么名字?你好李焕英
- 第一个 .next() 启动了 generator 的执行……执行到达第一个 yield 。
- 结果被返回到外部代码中。
- 第二个 .next(4) 将 4 作为第一个 yield 的结果传递回 generator 并恢复 generator 的执 行。
- ...以此类推
嵌套的generator,如何交换控制权,来看《JavaScript忍者秘籍第二版》的很经典的一个例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Generator函数</title> </head> <body> <div id="box"> <form action=""> <label for=""> <input type="text"> </label> <button>提交</button> </form> <p>Generator</p> </div> <script> var box = box || document.getElementById('box'); function* traverseTree(element) { yield element; element = element.firstElementChild; while (element) { yield* traverseTree(element); element = element.nextElementSibling; } } const subTree = traverseTree(box); for (const element of subTree) { console.log(element.nodeName); /** * DIV * FORM * LABEL * INPUT * BUTTON * P */ } </script> </body> </html>
我们可以通过yield* 将当前generator函数的控制权转移到下一个generator函数中,让我们再来看一下不用生成器函数的遍历方法,代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Generator函数</title> </head> <body> <div id="box"> <form action=""> <label for=""> <input type="text" /> </label> <button>提交</button> </form> <p>Generator</p> </div> <script> var box = box || document.getElementById("box"); function domTraverse(element, callback) { callback(element); element = element.firstElementChild; while (element) { domTraverse(element, callback); element = element.nextElementSibling; } } domTraverse(box, (element) => { console.log(element.nodeName); /** * DIV * FORM * LABEL * INPUT * BUTTON * P */ }); </script> </body> </html>
通过这两段代码可以看出,我们通过生成器函数将生产值(HTML节点) 与消费值(for 循环打印 访问过的节点名称)的代码分隔开,使得代码解耦;
我们还可以通过generator抛出错误,代码如下:
function* generator() { try { var result = yield '你喜欢JavaScript吗'; if (result == '喜欢') yield '太棒了!' else yield '真遗憾' }catch(e) { console.log('出错了!'); console.log(e); } } const gen = generator(); console.log( gen.next(), ) gen.throw(new Error('故意抛出错误!')); //出错了,Error:......