ES6之生成器(Generator)
来源:互联网 发布:程序员出书能赚钱吗 编辑:程序博客网 时间:2024/05/24 04:49
生成器(Generator)
目录:
- 生成器Generator
- 概念
- 生成器函数 Generator Function
- 生成器 Generator
- 使用方法
- 构建生成器函数
- 启动生成器
- 运行生成器内容
- 深入理解
- 运行模式
- 生成器函数以及生成器对象的检测
- 新语法 yield
- 生成器与协程
概念
通过一段程序,持续迭代或枚举出符合某个公式或算法的有序数列中的元素。
function* fibo(){ let a = 0; let b = 1; yield a; yield b; while(true){ let next = a + b; a = b; b = next; yield next; }}let generator = fibo();for(let i = 0; i < 10; i++){ console.log(generator.next().value); // 0 1 1 2 3 5 8 13 21 34}
生成器函数 (Generator Function)
生成器函数和普通函数的语法差别在于,在 function 语句之后和函数名之前有一个“*”作为生成器函数的标示符。
function* fibo(){ // ...}
生成器函数也可以使用表达式进行定义:
const fnName = function* (){ /* ... */ }
yield 语句的作用与 return 语句有些相似,但并非退出函数体,而是切出当前函数的运行时(此处为一个类的协程,Semi-coroutime),与此同时可以将一个值(可以是任何类型)带到主线程中。
生成器 (Generator)
生成器是一种类协程或半协程(Semi-coroutine),它提供了一种可以通过特定语句或方法使其执行对象(Execution)暂停的功能,而这语句一般都是 yield 语句。
在 ES6 中,yield 语句可以将一个值带出协程,而主线程也可以通过生成器对象的方法将一个值带回生成器的执行对象中去。
const inputValue = yield outputValue;
生成器切出执行对象并带出 outputValue ,主线程经过同步或异步处理后,通过 .next(val) 方法将 inputValue 带回生成器的执行对象中。
使用方法
构建生成器函数
function* genFn(){ let a = 2; yield a; // 为了使生成器能够根据公式不断输出数列元素所以指定条件为 true 保持程序不断执行 while(true){ yield a = a / (2 * a + 1); }}
在定义首项为2之后,首先将首项通过 yield 作为第一个值切出,其后通过循环和公式将每一项输出。
启动生成器
生成器函数不能直接作为普通函数来使用,因为在调用时无法直接执行其中的逻辑代码。执行生成器函数会返回一个生成器对象,用于运行生成器内容和接受其中的值。
const gen = genFn();
生成器是通过生成器函数实现的一个生成器(类)实例。
伪代码:
class Generator{ next(value) throw(error) [@@iterator]()}
其中 .next(value) 方法会返回一个状态对象,包含当前生成器的运行状态和所返回的值。
{ value: Any, done: Boolean}
生成器执行对象会不断检查生成器的状态,一旦遇到生成器内的最后一个 yield 语句或第一个 return 语句便会进入终止状态,即状态对象中的 done 属性会从 false 变为 true。
而 .throw(error) 方法会提前让生成器进入终止状态,并将 error 作为错误抛出。
运行生成器内容
生成器对象自身也是一种可迭代对象,我们直接使用 for-of 循环便可遍历。
for(const a of gen){ if(a < 1/100) break; console.log(a);}// 2// 0.4// 0.22222222222222224// ....
深入理解
运行模式
生成器函数以及生成器对象的检测
function* genFn(){ let a = 2; yield a; while(true){ yield a = a / (2 * a + 1); }}const gen = genFn();console.log(genFn().constructor.prototype); // GeneratorFunctionconsole.log(gen.constructor.prototype); // Generator// 检测生成器函数function isGeneratorFunction(fn){ const genFn = (function* (){}).constructor; return fn instanceof genFn;}console.log(isGeneratorFunction(genFn)); // true// 检测生成器实例对象function isGenerator(obj){ return obj.toString ? obj.toString() === '[object Generator]' : false;}console.log(isGenerator(gen)); // trueconsole.log(isGenerator({})); // false
使用@@toStringTag 属性来对生成器函数进行类型检测。
// 优化版function isGeneratorFunction(fn){ // If the current engine supports Symbol and @@toStringTag if(Symbol && Symbol.toStringTag){ return fn[Symbol.toStringTag] === 'GeneratorFunction'; } // Using instanceof statement for detecting const genFn = (function* (){}).constructor; return fn instanceof genFn;}
新语法 yield*
它和 yield 的区别在于, yield* 的功能是将一个生成器对象嵌套在另一个生成器内,并将其展开。
function* foo(){ yield 1; yield 2;}function* bar(){ yield* foo(); yield 3; yield 4;}for(const n of bar()) console.log(n);// 1// 2// 3// 4
生成器与协程
为了实现以生成器作为逻辑执行主体,把异步方法带到主线程去,就要先将异步函数做一层包装,使得其可以在带出生成器执行对象之后再执行。
// Beforefunction echo(content, callback){ callback(null, content);}// Afterfunction echo(content){ return callback => { callback(null, content); }}
将方法带出生成器执行对象后,还需要在主线程将带出的函数执行。上面我们通过封装所得到的异步方法再生成器内部执行后,可以通过 yield 语句将内层的函数带到主线程中,这样就可以在主线程中执行这个函数并得到返回值,然后将其返回到生成器执行对象中。
function run(genFn){ const gen = genFn(); const next = value => { const ret = gen.next(value); if(ret.done) return; ret.value((err, val) => { if(err) return console.error(err); // Loop next(val); }) } // First call next();}run(function* (){ const msg1 = yield echo('Hello'); const msg2 = yield echo(`${msg1} World`); console.log(msg2); // Hello World})
- ES6之生成器(Generator)
- ES6(三) Generator (生成器)函数
- ES6新特性之生成器函数 (generator function)- function-
- es6 之 Generator(一)
- es6 之 Generator(二)
- JS之Generator(生成器)
- ES6中的迭代器(Iterator)和生成器(Generator)
- 12、ES6 之Generator
- ES6之Generator
- python高级特性之生成器(generator)
- Python之生成器Generator
- es6 Generator (十五)
- Python 生成器(generator)
- 生成器(Generator)
- javascript---生成器(generator)
- 生成器函数(generator)
- 学习笔记:ES6之Generator
- es6新特性之generator
- 线程基础知识
- Ensemble Learning方法总结
- 输入不同对象的姓名、性别、年龄、体重和住址等信息,并输出显示。
- 算法导论课后习题答案
- Monkey和MonkeyRunner
- ES6之生成器(Generator)
- C++11特性
- Effective STL学习笔记-条款32
- Python 3.X 基础(三)
- RabbitMQ Publish/Subscribe
- 非常强大的人工栈模板,不看白不看!!!!
- 11月8日心得
- 天馈系统简介
- 异常处理