Generator原型
方法
基本使用
-
Generator对象与一种函数密切相关 Generator函数。我们在执行Generator函数,该函数不会立刻执行,而是会返回一个Generator对象。我们通过操作Generator对象来控制Generator函数的运行
-
Generator函数的函数体中,通过yield关键字将函数的执行过程分成了好几个阶段。
-
当我们调用Generator对象的next方法时,Generator函数会向下执行,直至遇到关键字yield就停止,并且返回关键字yield后面的表达式的值。
/** * Generator函数定义 */ function* gen() { yield 1; yield 2; yield 3; } // 执行Generator函数,返回一个Generator对象 var g = gen(); // [object GeneratorFunction] 查看gen类型 console.log(Object.prototype.toString.call(gen)); // [object Generator] 查看g类型 console.log(Object.prototype.toString.call(g)); // 1 console.log(g.next().value); // 2 console.log(g.next().value); // 3 console.log(g.next().value); // undefined console.log(g.next().value);
-
我们可以为Generator对象在执行next方法执行时传入参数,作为函数下一个阶段运行的输入
// 定义Generator函数 function *gen(){ yield 1; let i = yield 2; yield i; } // 执行函数,该函数返回Generator对象 var g = gen(); // 1 console.log(g.next().value); // 2 console.log(g.next().value); // 12 console.log(g.next(12).value);
-
而当生成器函数显示return时,该函数立即变为完成状态。且return返回的值是此次调用iterator.next()返回对象的属性名为value的值。
// 定义Generator函数 function *gen(){ yield 1; yield 2; return 14; yield 3; } // 执行函数,该函数返回Generator对象 var g = gen(); // 1 console.log(g.next().value); // 2 console.log(g.next().value); // 14 console.log(g.next().value);
高级用法
-
函数执行权转移
我们可以通过Generator函数来实现函数执行时执行函数主体的转移
// 定义Generator函数 gen1 function *gen1(){ yield "gen1 1"; yield "gen1 2"; yield "gen1 3"; } // 定义Generator函数 gen2 function *gen2(){ yield "gen2 1"; yield* gen1(); yield "gen2 3"; } // 执行gen2函数返回一个Generator对象 var g = gen2(); // gen2 1 console.log(g.next().value); // gen1 1 console.log(g.next().value); // gen1 2 console.log(g.next().value); // gen1 3 console.log(g.next().value); // gen2 3 console.log(g.next().value); // undefined console.log(g.next().value);
-
将嵌套数组转化为扁平一维数组,来自MDN
function* iterArr(arr){ if(Array.isArray(arr)){ for(let i=0;i<arr.length;i++){ yield* iterArr(arr[i]); } }else{ yield arr; } } var arr = ['a', ['b', 'c'], ['d', 'e']]; var gen = iterArr(arr); arr = [...gen];
-
遍历二叉树,来自阮一峰老师的es6
// 下面是二叉树的构造函数, // 三个参数分别是左树、当前节点和右树 function Tree(left, label, right) { this.left = left; this.right = right; this.label = label; } // 下面是中序(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); } console.log(result);
-
使用Generator构建构造函数,来控制实例对象的实例化过程
// Generator函数 function *gen(){ yield this.a = 1; yield this.b = 2; yield this.c = 3; } // 构造函数F function F(){ // 在当前对象挂载一个属性next,用于控制gen函数的运行 this.next = gen.call(this); } // 使用构造函数F var f = new F(); // F {next: gen} console.log(f); // 运行gen函数 f.next.next(); // F {next: gen, a: 1} console.log(f); // 运行gen函数 f.next.next(); // F {next: gen, a: 1, b: 2} console.log(f); // 运行gen函数 f.next.next(); // F {next: gen, a: 1, b: 2, c: 3} console.log(f);
-
使用Generator来实现异步编程
我们可以使用Generator函数来控制异步操作的工作流程
// 异步操作函数f1 function f1() { return new Promise((resolve, reject) => { setTimeout(() => { console.log("f1") resolve("第一阶段异步工作完成") }, 3000); }); } // 异步操作函数f2 function f2() { return new Promise((resolve, reject) => { setTimeout(() => { console.log("f2") resolve("第二阶段异步工作完成") }, 3000); }); } // 异步操作函数f3 function f3() { return new Promise((resolve, reject) => { setTimeout(() => { console.log("f3") resolve("第三阶段异步工作完成") }, 3000); }); } // 操控一系列异步操作流程的Generator函数 function *gen(){ yield f1(); yield f2(); yield f3(); } // 执行Generator函数,返回Generator对象 var g = gen(); // 开始异步第一阶段操作 g.next().value.then((res)=>{ console.log(res); // 异步第一阶段操作完成,开始异步第二阶段操作 return g.next().value }).then((res)=>{ console.log(res); // 异步第二阶段操作完成,开始异步第三阶段操作 return g.next().value; }).then((res)=>{ console.log(res); }).catch((err)=>{ console.log(err); }) // 同步执行 console.log("hello world");
Generator对象和Generator函数
// Generator函数
function* gen() {
yield 1;
yield 2;
yield 3;
}
// 执行Generator函数,返回Generator对象
var g = gen();
// [object Generator]
console.log(Object.prototype.toString.call(g));
// [object GeneratorFunction]
console.log(Object.prototype.toString.call(gen));
// true
/**
* 这个结果说明g的__proto__属性指向函数gen的原型
* 可以与构造函数与由构造函数创建的实例对象进行比较
*/
console.log(g.__proto__ == gen.prototype);
// 构造函数A
function A(){
this.a = 1;
this.b = 2;
}
// 实例对象a
var a = new A();
// true
console.log(a.__proto__ == A.prototype);
上面的输出结果结果说明,generator实例对象是指向generator函数的原型,而generator函数的原型就是对象Generator