码迷,mamicode.com
首页 > 编程语言 > 详细

[JavaScript]ECMA-6 yield语法

时间:2019-01-18 18:26:48      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:archive   二次   位置   就会   get   result   exe   script   undefined   

概述

      yield关键字用于并且仅限于生成器函数(generator)内部,作用是暂停(并返回)/重启(可选修改该栈环境变量)该函数栈环境。

一般语法

     调用生成器函数时返回一个可迭代对象,当调用该对象的next()方法时,函数会在遇到yield关键字的位置马上返回一个IteratorResult对象,该对象格式如下:

{value: [Mixed], done: [boolean]}

     yield的行为类似于return,不同的地方在于,yield返回后并不等同于该次函数调用的结束,该函数的栈环境仍然存在于内存当中(暂停),等待下一次调用到来时,代码段将会在上一次yield返回的位置继续往下执行(重启),

这样就实现了函数的暂停/重启行为。

function* foo(index) {
   let a = 2;
   while (index < a) {
      c = yield index++;
    }
}

const iterator = foo(0);

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

     输出:

{value: 0, done: false}
{value: 1, done: false}
{value: undefined, done: true}

     可见每次调用next()都会在yield处返回该变量的结果并不再往下执行,当下次调用next()时,该函数会在上一次yield的位置继续往下执行,直到函数真正执行完毕,返回对象的done属性被赋值为true。

改变函数内部变量

     yield还有另外一种能力,就是改变该函数栈内变量的值

[rv] = yield [expression];

     调用next()时接受一个参数

generator.next([vaule]);

     这样多次调用(除第一次)时,就会先把vaule赋值给函数内部变量rv再继续往下执行

 

     示例:

function* foo(index) {
      let a = 2;
      var b;
      while (index < a) {
          b = yield b;
      }
}

const iterator = foo(0);

console.log(iterator.next(‘a‘));
console.log(iterator.next(‘b‘));
console.log(iterator.next(‘c‘));

     输出:

{value: undefined, done: false}
{value: "b", done: false}
{value: "c", done: false}

     当yield前加=号赋值给函数内部某个变量时,在第一次调用将不会给该变量赋予任何形式的值,所以在这里的第一行输出时,value等于undefined,并不是设想的被赋值为a。让next([vaule])真正起作用,是在多次调用的时候,在重启函数时,先把该函数栈内的rv变量赋值为value后再继续执行。这有点类似于Python的nex()和send(),只不过ECMA-6只用了next()来实现这种功能。

     这里有一个难点,就是难以理解rv是何时改变它的值的,为了更清晰的说明这个问题,我们更改一下上面的例子,在yield前输出一下变量b

function* foo(index) {
  let a = 2;
  var b;
  while (index < a) {
      console.log(b);
      b = yield b;
  }
}

const iterator = foo(0);

console.log(iterator.next(‘a‘));
console.log(iterator.next(‘b‘));
console.log(iterator.next(‘c‘));

     输出:

undefined
{value: undefined, done: false}
b
{value: "b", done: false}
c
{value: "c", done: false}

     可以看见,除了第一次调用,其他的调用都遵循一种原则:先改变该栈环境内的rv变量,再继续执行代码

return yield 

     有一种情况,就是该类函数如果包含return语句又会怎样呢?我们来看看MDN对这个行为的描述:

  • A return statement is reached. In this case, execution of the generator ends and an IteratorResult is returned to the caller in which the value is the value specified by the return statement and done is true.

     如预料之中的一样,return会终止函数,并返回return语句的结果,放置在IteratorResult.vaule上,同时这也意味着整个迭代结束,IteratorResult.done为true.

     但是,如果是return yield [statement]呢?来看看下面的例子:

 

function* foo(index) {
         let a = 3;
      while (index < a) {
          return yield index++;
      }
}

const iterator = foo(0);

console.log(iterator.next(‘a‘));
console.log(iterator.next(‘b1‘));
console.log(iterator.next(‘c‘));

 

     输出:

{value: 0, done: false}
{value: "b1", done: true}
{value: undefined, done: true}

     如果结合上小段介绍,即“改变函数内部变量”,就不难理解这个例子的行为;

     在第一次调用,next()返回未经递增的index,即0,并且暂停函数;

     第二次调用,重启函数,把参数的值"b1"赋值给函数栈环境的变量,但是由于这里遇到的是return,所以"b1"自然而然的返回给了IteratorResult.vaule,并且结束整个迭代;

     第三次调用,由于迭代已经结束,所以这里的调用已经没有任何意义;

 

[JavaScript]ECMA-6 yield语法

标签:archive   二次   位置   就会   get   result   exe   script   undefined   

原文地址:https://www.cnblogs.com/yiyide266/p/10260337.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!