金沙检测线路js此时undefined / 2为NaN

当前位置:金沙检测线路411166 > 金沙检测线路js > 金沙检测线路js此时undefined / 2为NaN
作者: 金沙检测线路411166|来源: http://www.kemates.com|栏目:金沙检测线路js

文章关键词:金沙检测线路411166,完全解析函数

  Generator函数是ES6提供的一种异步编程解决方案,语法与传统函数完全不同。金沙检测线路js以下会介绍一下Generator函数。

  写下这篇文章的目的其实很简单,是想梳理一下自己对于Generator的理解,同时呢,为学习async函数做一下知识储备。

  对于Generator函数(也可以叫做生成器函数)的理解,可以从四个方面:

  形式上:Generator函数是一个普通的函数,不过相对于普通函数多出了两个特征。一是在function关键字和函数明之间多了*号;二是函数内部使用了yield表达式,用于定义Generator函数中的每个状态。

  语法上:Generator函数封装了多个内部状态(通过yield表达式定义内部状态)。执行Generator函数时会返回一个遍历器对象(Iterator对象)。也就是说,Generator是遍历器对象生成函数,函数内部封装了多个状态。通过返回的Iterator对象,可以依次遍历(调用next方法)Generator函数的每个内部状态。

  调用上:普通函数在调用之后会立即执行,而Generator函数调用之后不会立即执行,而是会返回遍历器对象(Iterator对象)。通过Iterator对象的next方法来遍历内部yield表达式定义的每一个状态。

  yield,英文意思即产生、退让的意思,因此yield表达式也有两种作用:定义内部状态和暂停执行。

  从上面代码中可以看出,gen函数使用yield表达式定义了两个内部状态。同时呢,也可以看出来,return语句只能有一个,而yield表达式却可以有多个。

  执行gen函数之后,会返回一个遍历器对象,而不是立即执行gen函数。如果需要获取yield表达式定义的每个状态,需要调用next方法。

  每调用一次next方法都会返回一个包含value和done属性的对象,此时会停留在某个yield表达式结尾处。value属性值即是yield表达式的值;done属性是布尔值,表示是否遍历完毕。

  另外呢,yield表达式没有返回值,或者说返回值是undefined。待会会说明一下如何给yield表达式传递返回值。

  需要注意的是,yield表达式的值,只有调用next方法时才能获取到。因此等于为JavaScript提供了手动的惰性求值(Lazy Evaluation)的功能。

  一般情况下,Generator函数会结合yield表达式使用,通过yield表达式定义多个内部状态。但是,如果不使用yield表达式的Generator函数就成为了一个单纯的暂缓执行函数,个人感觉没什么意义...

  另外,yield表达式如果用在另一个表达式中,需要为其加上圆括号。作为函数参数和语句是可以不使用圆括号。

  yield表达式具有暂停执行的功能,而恢复执行的是next方法。每一次调用next方法,就会从函数头部或者上一次停下来的地方开始执行,直到遇到下一个yield表达式(return 语句)为止。同时,调用next方法时,会返回包含value和done属性的对象,value属性值可以为yield表达式、return语句后面的值或者undefined值,done属性表示遍历是否结束。

  遍历器对象的next方法(从Generator函数继承而来)的运行逻辑如下

  遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield表达式后面的那个表达式的值,作为返回的对象的value属性值。

  下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。

  如果没有再遇到新的yield表达式,就一直运行到函数结束,直到遇到return语句为止,并将return语句后面表达式的值,作为返回的对象的value属性值。

  如果该函数没有return语句,则返回的对象的value属性值为undefined。

  也就是说,如果有yield表达式,则value属性值就是yield表达式后面的指;如果没有yield表达式,value属性值就等于return语句后面的值;如果yield表达式和return语句都不存在的话,则value属性值就等于undefined。举个例子: )

  根据next运行逻辑再针对这个例子,就很容易理解了。调用gen函数,返回遍历器对象。

  第一次调用next方法时,在遇到第一个yield表达式时停止执行,value属性值为1,即yield表达式后面的值,done为false表示遍历没有结束;

  第二次调用next方法时,金沙检测线路js从暂停的yield表达式后开始执行,直到遇到下一个yield表达式后暂停执行,value属性值为2,done为false;

  第三次调用next方法时,从上一次暂停的yield表达式后开始执行,由于后面没有yield表达式了,所以遇到return语句时函数执行结束,value属性值为return语句后面的值,done属性值为true表示已经遍历完毕了。

  第四次调用next方法时,value属性值就是undefined了,此时done属性为true表示遍历完毕。以后再调用next方法都会是这两个值。

  从上面代码可以看出,第一次调用next方法时,value属性值是hello world,第二次调用时,由于变量y的值依赖于变量x,而yield表达式没有返回值,所以返回了undefined给变量x,此时undefined / 2为NaN。

  要解决上面的问题,可以给next方法传递参数。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。

  当给第二个next方法传递参数10时,yield表达式的返回值为10,即var x = 10,所以此时变量y为5。

  注意,由于next方法的参数表示上一个yield表达式的返回值,所以在第一次使用next方法时,传递参数是无效的。V8引擎直接忽略第一次使用next方法的参数,只有从第二次使用next方法开始,参数才是有效的。从语义上说,第一个next方法用来启动遍历器对象,所以不用带上参数。所以呢,每次使用next方法会比yield表达式要多一次。

  实际上,yield表达式和next方法构成了双向信息传递。yield表达式可以向外传递value值,而next方法参数可以向内传递值。

  从上面代码中可以看出,并没有在yield 1处停止执行。此时就需要使用yield* 表达式。从语法角度上说,如果yield表达式后面跟着遍历器对象,需要在yield表达式后面加上星号,表明它返回的是一个遍历器对象。实际上,yield*表达式是for...of循环的简写,完全可以使用for...of循环来代替yield*表达式

  如果直接使用了yield foo(),返回的对象的value属性值为一个遍历器对象。而不是Generator函数的内部状态。

  任何一个对象的Symbol.iterator属性,指向默认的遍历器对象生成函数。而Generator函数也是遍历器对象生成函数,所以可以将Generator函数赋值给Symbol.iterator属性,这样就使对象具有了Iterator接口。默认情况下,对象是没有Iterator接口的。金沙检测线路js

  Generator函数函数执行之后,会返回遍历器对象。该对象本身也就有Symbol.iterator属性,执行后返回自身

  上面代码使用for...of循环,依次显示 3 个yield表达式的值。这里需要注意,一旦next方法的返回对象的done属性为true,for...of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的6,不包括在for...of循环之中。

  Generator函数中的this对象跟构造函数中的this对象有异曲同工之处。先来看看构造函数中的new关键字的工作原理。

  调用Generator函数会返回遍历器对象,而不是实例对象,因此无法获取到this指向的实例对象上的私有属性和方法。但是这个遍历器对象可以继承Generator函数的prototype原型对象上的属性和方法(公有属性和方法)。

  如果希望修复this指向性问题,可以使用call方法将函数执行时所在的作用域绑定到Generator.prototype原型对象上。这样做,会使私有属性和方法变成公有的了,因为都在原型对象上了。

  Generator函数的应用主要在异步编程上,会在下一篇文章中分享。请期待噢: )

网友评论

我的2016年度评论盘点
还没有评论,快来抢沙发吧!