zoukankan      html  css  js  c++  java
  • Generator函数的语法

    简介

    Generator函数是ES6关于异步编程的解决方案。Generator函数能够让函数暂停执行(即交出函数的执行权),简单直白点来理解,Generator函数就是一个状态机,内部封装了多个状态(暂停执行的位置)

    • 定义:
    1. function 关键字后有一个*
    2. 函数体内部有yield表达式,表示暂停的位置,定义不同状态。
    function* helloWorld(){
        yield 'hello';
        yield 'world';
        return 'end';
    }
    var hw = helloWorld();
    
    • 调用
    1. 通过next()方法调用,返回结果形如{value:xxx, done: bool}。并在下一个yield处暂停。
    2. 当函数执行完毕(碰到return或者所有yield执行完毕),那么返回的结果value为return的值(无return 则返回undefined),done为true。
    3. 函数执行完毕后无论怎么调用next()方法,结果都是{ value: undefined, done: true }
    4. 通过next()可以传入参数进入状态机,即传入值取代yield表达式。
    hw.next();
    //{value:'hello',done:false}
    hw.next();
    //{value:'world',done:false}
    hw.next();
    //{value:'end',done:true}
    hw.next()
    //{value:'undefined',done:true}
    
    • yield*表达式
      yield*表达式用于在Generator函数内部调用另外一个Generator函数。

    • throw()方法
      在函数体外部抛出错误,如果内部有catch语句,那么优先内部捕获,否则为外部捕获。全局的throw命令只能够外部catch捕获

    • return()方法
      用于终结遍历Generator函数。Generator函数调用return方法后,那么返回值的done变为true,遍历终止。
      当内部有try...finally代码块时,return会推迟到finally代码块执行完后再执行。

    function* numbers () {
      yield 1;
      try {
        yield 2;
        yield 3;
      } finally {
        yield 4;
        yield 5;
      }
      yield 6;
    }
    var g = numbers();
    g.next() // { value: 1, done: false }
    g.next() // { value: 2, done: false }
    g.return(7) // { value: 4, done: false }
    g.next() // { value: 5, done: false }
    g.next() // { value: 7, done: true }
    
    • 其他
    1. yield只能在Generator函数内使用
    2. Generator函数执行后会返回一个遍历器对象,通过把Generator函数赋值给对象的Symbol.iterator属性,即可使对象获得Iterator接口,可以被for...of...等遍历

    应用

    1. 利用Generator遍历Object的属性

    function* objectEntries(obj) {
      let propKeys = Reflect.ownKeys(obj);
      
      for (let propKey of propKeys) {
        yield [propKey, obj[propKey]];
      }
    }
    
    let jane = { first: 'Jane', last: 'Doe' };
    
    for (let [key, value] of objectEntries(jane)) {
      console.log(`${key}: ${value}`);
    }
    

    2. 利用yield*遍历嵌套数组

    let arr = [1,2,[3,4,5,[6,7,8],9],10];
    
    function* iterArr(arr){
    	for(let value of arr){
    		if(Array.isArray(value)){
    			yield* iterArr(value);
    		}else{
    			yield value;
    		}
    	}
    }
    for(let x of iterArr(arr)){
    	console.log(x);
    }
    

    3. 利用yield*中序遍历完全二叉树

    //节点的构造函数
    
    function Node(left, value, right){
    	this.left = left;
    	this.value = value;
    	this.right = right;
    }
    //完全二叉树遍历函数
    function* inorder(node){
    	if(node){
    		yield* inorder(node.left);
    		yield node.value;
    		yield* inorder(node.right);
    	}
    }
    
    //二叉树生成函数
    function binaryTree(arr){
    	if(arr.length === 1){
    		return new Node(null, arr[0], null);
    	}
    	return new Node(binaryTree(arr[0]),arr[1],binaryTree(arr[2]));
    }
    
    let tree = binaryTree([[['a'], 'b', ['c']], 'd', [['e'], 'f', ['g']]]);
    
    console.log(tree);
    
    let result = [];
    for (let node of inorder(tree)){
    	result.push(node);
    }
    console.log(result);
    

    4. Generator函数的状态机实现

    Generator 的确是用来实现状态机的最佳数据结构。

    首先,在没有外部输入的情况,一个状态机只有内部既定的逻辑,与Generator函数一样:若未经处理,那么也是一个按照既定顺序执行的多阶段的任务队列。

    通过yield 可以表示状态机的状态,利用yield来接受外界对Generator的输入,即状态机接受外部的输入参数。
    然后通过内部的逻辑,将之切换到不同的下一个yield,即可实现状态机的切换。

    提供一个利用Generator函数实现的简单状态机案例:

    • 状态机的状态变化如下图所示:

    • Generator函数模拟
    let machine = function* (){
    	let states = ['初始化','状态一', '状态二', '状态三', '状态四', '退出'];
    	let i = 0;
    	let input = yield states[0];
    	while(true){
    		if(typeof input !== 'number'){
    			input = 0;
    		}
    		switch (i) {
    			case 1:
    				if(input <= 0) i = 3;
    				else if(input > 10) i = 2;
    				else if(input > 100) i = 4;
    				break;
    
    			case 2:
    				if(input > 10) i = 4;
    				break;
    			case 3:
    				if(input > 10) i = 4;
    				else if(input < 0) i = 1;
    				break;
    			case 4:
    				if(input > 100) i = 1;
    				if(input < -100){
    					yield states[5];
    					return '状态机关闭';
    				}
    				break;
    			default:
    				i = 1;
    				break;
    		}
    		input = yield states[i];
    	}
    };
    machine = machine();
    console.log(machine.next());
    
    • 函数执行结果:

    参考文献

    1. ECMAScript 6入门--第16章 Generator函数的语法
  • 相关阅读:
    POJ 1328 Radar Installation
    POJ 1700 Crossing River
    POJ 1700 Crossing River
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3069 Saruman's Army(贪心)
    poj 3069 Saruman's Army(贪心)
    Redis 笔记与总结2 String 类型和 Hash 类型
    数据分析方法有哪些_数据分析方法
    数据分析方法有哪些_数据分析方法
  • 原文地址:https://www.cnblogs.com/omg-two/p/6875617.html
Copyright © 2011-2022 走看看