博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Generator函数
阅读量:6229 次
发布时间:2019-06-21

本文共 5083 字,大约阅读时间需要 16 分钟。

本系列属于阮一峰老师所著的学习笔记


概念

Generator函数是ES6提供的一种异步编程解决方案。形式上,Generator函数是一个普通函数,但是有两个特征:function关键字与函数名之间有一个星号;函数体内部使用yield表达式,定义不同的内部状态(yield表意产出)。

function* helloWorldGenerator(){  yield 'hello'  yield 'world'  return 'ending'}var hw = helloWorldGenerator()// Generator函数和普通函数一样调用,但是调用后函数并不执行,返回一个指向内部状态的指针对象,即遍历器对象(Iterator Object)hw.next() // {value: 'hello',done:false}hw.next() // {value: 'world',done:false}hw.next() // {value: 'ending',done:true}hw.next() // {value: undefined,done:true}// 每次调用next方法,执行Generator函数,依次返回yeild表达式的值,执行到return语句(若没有return语句就执行到结束)
yield表达式

Generator函数返回遍历器对象,只有调用next方法才会遍历下一个状态,yield表达式就是暂停函数执行的暂停标志。

Generator函数可以不用yield表达式,这时就变成一个单纯的暂缓执行函数

function* f(){  console.log('done!')}var generator = f() // 函数不会立即执行,只有调用next方法才会执行setTimeout(function(){  generator.next()},2000)

yield表达式如果在另一个表达式中,必须放在圆括号内

function* demo(){  console.log('Hello' + yield) // SyntaxError  console.log('Hello' + (yield)) // OK}// yield表达式用作函数参数或放在赋值表达式的右边,可以不加括号function* demo(){  foo(yield 'a',yield 'b') // OK  let input = yield // OK}
与Iterator接口的关系

任何一个对象的Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。由于Generator函数就是遍历器生成函数,因此可以把Generator函数赋值给Symbol.iterator属性,从而使得该对象具有iterator接口。

var myIterator = {}myIterator[Symbol.iterator] = function* (){  yield 1  yield 2  yield 3}[...myIterator] // [1,2,3]
next方法的参数

yield表达式本身没有返回值,或者说每次都返回undefined。next方法可以带一个参数,该参数会被当做上一个yield表达式的返回值

function* f() {  for(var i = 0; true; i++) {    var reset = yield i;    if(reset) { i = -1; }  }}var g = f();g.next() // { value: 0, done: false }g.next() // { value: 1, done: false }g.next(true) // { value: 0, done: false }// 每次运行到yield表达式,变量reset总被赋值undefined,当next带上参数之后,遍历reset就被赋值为true
for...of循环

for...of循环可以自动遍历Generator函数生成的Iterator对象,且不用再调用next方法

function* foo(){  yield 1  yield 2  yield 3  yield 4  return 5}for(let v of foo()){  console.log(v)}// 1 2 3 4// for...of循环遇到next方法返回对象的done为true就会中止,所以return返回的5不在循环之中// 除了for...of循环外,拓展运算符...、解构赋值和Array.from都可以将Generator函数返回的Iterator对象作为参数function* numbers () {  yield 1  yield 2  return 3  yield 4}// 拓展运算符[...numbers()] // [1,2]// Array.fromArray.from(numbers()) // [1,2]// 解构赋值let [x,y] = numbers()x // 1y // 2// for...of循环for(let n of numbers()){  console.log(n) // 1 2}
Generator.prototype.throw()

Generator函数返回的遍历器对象有一个throw方法,可以在函数体外抛出错误,然后在函数体内捕获

var g = function* (){  try{    yield  }catch(e){    console.log('内部捕获',e)  }}var i = g()i.next()// throw方法可以接收一个参数,改参数会被catch语句接收,建议抛出Error对象实例try {  i.throw('a')  i.throw('b')}catch(e){  console.log('外部捕获',e)}// 内部捕获 a// 外部捕获 b// throw方法被捕获后会附带执行下一条yield表达式,也就是说会附带执行一次next方法
Generator.prototype.return()

return方法返回给定的值,并且终结遍历Generator函数

function* gen(){  yield 1  yield 2  yield 3}var g= gen()g.next() // {value:1,done:false}g.return('foo') // {value:'foo',done:true}g.next() // {value:undefined,done:true}// 如果Generator函数内部有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}
yield* 表达式

在Generator函数内调用另一个Generator函数,默认情况下是没有效果的,这时候就要用到yield*表达式

function* inner(){  yield 'hello!'}function* outer1(){  yield 'open'  yield inner()  yield 'close'}var gen = outer1()gen.next().value // 'open'gen.next().value // 返回一个遍历器对象gen.next().value // 'close'function* outer2(){  yield 'open'  yield* inner()  yield 'close'}var gen = outer2()gen.next().value // 'open'gen.next().value // 'hello'gen.next().value // ’close'function* concat(iter1,iter2){  yield* iter1  yield* iter2}// 等同于function* concat(iter1,iter2){  for(var value of iter1){    yield value  }  for(var value of iter2){    yield value  }}function* gen(){  yield* ['a','b','c']}gen().next() // {value:'a',done:false}// 若不加星号返回的是整个数组,加了就表示返回的是数组的遍历器对象。实际上任何具有Iterator接口的数据结构都可以被yield遍历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}//被代理的Generator函数foo有return语句,那么就会向代理它的Generator函数bar返回数据,并且继续执行next方法
作为对象属性的Generator函数
let obj = {  * myGeneratorMethod(){    ...  }}
Generator函数的this
// 生成空对象,使用call方法绑定Generator函数内部的thisfunction* F(){  this.a = 1  yield this.b = 2  yield this.c = 3}var obj = {}var f = F.call(obj)// 调用三次next方法完成F内部所有代码的运行,将所有内部属性绑定在obj对象上f.next() // {value:2,done:false}f.next() // {value:3,done:false}f.next() // {value:undefined,done:true}// obj对象编程了F的实例obj.a // 1obj.b // 2obj.c // 3// 将F改成构造函数,可以执行new命令function* gen(){  this.a = 1  yield this.b = 2  yield this.c = 3}function F(){  return gen.call(gen.prototype)}var f = new F()f.next() // {value:2,done:false}f.next() // {value:3,done:false}f.next() // {value:undefined,done:true}f.a // 1f.b // 2f.c // 3

转载于:https://www.cnblogs.com/pengzhixin/p/7698418.html

你可能感兴趣的文章
(一)spring cloud微服务分布式云架构 - Spring Cloud简介
查看>>
伪前端笔记
查看>>
Spark之join、leftOuterJoin、rightOuterJoin及fullOuterJoin
查看>>
20172307 2018-2019-1 《程序设计与数据结构》实验1报告
查看>>
Kafka 0.9 新特性
查看>>
Angualr2 ChartModle图表
查看>>
如何准确高效的获取数据库新插入数据的主键id
查看>>
In-App Purchases验证
查看>>
数据库mysql进阶之路(2)--查询操作
查看>>
解决android模拟器无法上网问题
查看>>
跟我一起学习ASP.NET 4.5 MVC4.0(六)(转)
查看>>
Maven搭建SpringMVC + SpringJDBC项目详解
查看>>
初识swipe.js
查看>>
<Android Framework 之路>Android5.1 Camera Framework(四)——框架总结
查看>>
MySQL日期时间函数大全(转)
查看>>
Silverlight实例教程 - Validation数据验证基础属性和事件(转载)
查看>>
JAVA未来前景还能持续多久
查看>>
Sklearn学习笔记
查看>>
Android 内存优化 (防Memory Leak)
查看>>
C++之指针
查看>>