当前位置:K88软件开发文章中心编程语言JavaScriptECMAScript → 文章内容

ECMAScript 6 Generator 函数

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-15 15:38:37

{ yield* ["a", "b", "c"];}gen().next() // { value:"a", done:false }上面代码中,yield命令后面如果不加星号,返回的是整个数组,加了星号就表示返回的是数组的遍历器对象。实际上,任何数据结构只要有Iterator接口,就可以被yield*遍历。let read = (function* () { yield 'hello'; yield* 'hello';})();read.next().value // "hello"read.next().value // "h"上面代码中,yield语句返回整个字符串,yield*语句返回单个字符。因为字符串具有Iterator接口,所以被yield*遍历。如果被代理的Generator函数有return语句,那么就可以向代理它的Generator函数返回数据。function *foo() { yield 2; yield 3; return "foo";}function *bar() { yield 1; var v = yield *foo(); console.log( "v: " + v ); yield 4;}var it = bar();it.next()// {value: 1, done: false}it.next()// {value: 2, done: false}it.next()// {value: 3, done: false}it.next();// "v: foo"// {value: 4, done: false}it.next()// {value: undefined, done: true}上面代码在第四次调用next方法的时候,屏幕上会有输出,这是因为函数foo的return语句,向函数bar提供了返回值。再看一个例子。function* genFuncWithReturn() { yield 'a'; yield 'b'; return 'The result';}function* logReturned(genObj) { let result = yield* genObj; console.log(result);}[...logReturned(genFuncWithReturn())]// The result// 值为 [ 'a', 'b' ]上面代码中,存在两次遍历。第一次是扩展运算符遍历函数logReturned返回的遍历器对象,第二次是yield*语句遍历函数genFuncWithReturn返回的遍历器对象。这两次遍历的效果是叠加的,最终表现为扩展运算符遍历函数genFuncWithReturn返回的遍历器对象。所以,最后的数据表达式得到的值等于[ 'a', 'b' ]。但是,函数genFuncWithReturn的return语句的返回值The result,会返回给函数logReturned内部的result变量,因此会有终端输出。yield*命令可以很方便地取出嵌套数组的所有成员。function* iterTree(tree) { if (Array.isArray(tree)) { for(let i=0; i < tree.length; i++) { yield* iterTree(tree[i]); } } else { yield tree; }}const tree = [ 'a', ['b', 'c'], ['d', 'e'] ];for(let x of iterTree(tree)) { console.log(x);}// a// b// c// d// e下面是一个稍微复杂的例子,使用yield*语句遍历完全二叉树。// 下面是二叉树的构造函数,// 三个参数分别是左树、当前节点和右树function Tree(left, label, right) { this.left = left; this.label = label; this.right = right;}// 下面是中序(inorder)遍历函数。// 由于返回的是一个遍历器,所以要用generator函数。// 函数体内采用递归算法,所以左树和右树要用yield*遍历function* inorder(t) { if (t) { yield* inorder(t.left); yield t.label; yield* inorder(t.right); }}// 下面生成二叉树function make(array) { // 判断是否为叶节点 if (array.length == 1) return new Tree(null, array[0], null); return new Tree(make(array[0]), array[1], make(array[2]));}let tree = make([[['a'], 'b', ['c']], 'd', [['e'], 'f', ['g']]]);// 遍历二叉树var result = [];for (let node of inorder(tree)) { result.push(node);}result// ['a', 'b', 'c', 'd', 'e', 'f', 'g']作为对象属性的Generator函数如果一个对象的属性是Generator函数,可以简写成下面的形式。let obj = { * myGeneratorMethod() { ··· }};上面代码中,myGeneratorMethod属性前面有一个星号,表示这个属性是一个Generator函数。它的完整形式如下,与上面的写法是等价的。let obj = { myGeneratorMethod: function* () { // ··· }};Generator函数的thisGenerator函数总是返回一个遍历器,ES6规定这个遍历器是Generator函数的实例,也继承了Generator函数的prototype对象上的方法。function* g() {}g.prototype.hello = function () { return 'hi!';};let obj = g();obj instanceof g // trueobj.hello() // 'hi!'上面代码表明,Generator函数g返回的遍历器obj,是g的实例,而且继承了g.prototype。但是,如果把g当作普通的构造函数,并不会生效,因为g返回的总是遍历器对象,而不是this对象。function* g() { this.a = 11;}let obj = g();obj.a // undefined上面代码中,Generator函数g在this对象上面添加了一个属性a,但是obj对象拿不到这个属性。Generator函数也不能跟new命令一起用,会报错。function* F() { yield this.x = 2; yield this.y = 3;}new F()// TypeError: F is not a constructor上面代码中,new命令跟构造函数F一起使用,结果报错,因为F不是构造函数。那么,有没有办法让Generator函数返回一个正常的对象实例,既可以用next方法,又可以获得正常的this?下面是一个变通方法。首先,生成一个空对象,使用bind方法绑定Generator函数内部的this。这样,构造函数调用以后,这个空对象就是Generator函数的实例对象了。function* F() { this.a = 1; yield this.b = 2; yield this.c = 3;}var obj = {};var f = F.call(obj);f.next(); // Object {value: 2, done: false}f.next(); // Object {value: 3, done: false}f.next(); // Object {value: undefined, done: true}obj.a // 1obj.b // 2obj.c // 3上面代码中,首先是F内部的this对象绑定obj对象,然后调用它,返回一个Iterator对象。这个对象执行三次next方法(因为F内部有两个yield语句),完成F内部所有代码的运行。这时,所有内部属性都绑定在obj对象上了,因此obj对象也就成了F的实例。上面代码中,执行的是遍历器对象f,但是生成的对象实例是obj,有没有办法将这两个对象统一呢?一个办法就是将obj换成F.prototype。function* F() { this.a = 1; yield this.b = 2; yield this.c = 3;}var f = F.call(F.prototype);f.next(); // Object {value: 2, done: false}f.next(); // Object {value: 3, done: false}f.next(); // Object {value: undefined, done: true}f.a // 1f.b // 2f.c // 3再将F改成构造函数,就可以对它执行new命令了。function* gen() { this.a =

上一页  [1] [2] [3] [4] [5] [6] [7]  下一页


ECMAScript 6 Generator 函数