for循环中的函数发生器

时间:2018-12-28 22:03:22

标签: javascript for-loop generator

我试图更好地了解生成器在javascript中的工作方式。

来自MDN:

  

function *声明(function关键字后跟一个星号)   定义一个生成器函数,该函数返回一个Generator对象。

function *range(from, to) {
    var counter = from;
    while(to >= counter) {
        yield counter
        counter++
    }        
}

for (var r of range(5, 10)) {
    console.log( r );
}

// print: 5, 6, 7, 8, 9, 10

我不确定我如何确切地理解上面的代码片段中发生的事情。

不应该调用生成器,将其存储为(生成器)对象,然后通过next()方法进行调用。 (如下所示)

function *foo () {
      yield 'woo';
 }
 var G = foo();
 console.log( G.next() );

在上面的代码中,第4行带有var G = foo();,我调用一个函数并创建新的执行上下文,这应该只返回一个生成器对象(并将其存储在标签下) G)。

当我在第5行调用foo方法时,我将调用实际的函数next()。那时,我正在创建一个执行上下文,在{中执行代码{1}}并产生字符串foo

第一个代码段应该如何工作?

2 个答案:

答案 0 :(得分:3)

调用生成器函数将返回一个迭代器(具有.next函数的对象),并且for..of循环将自动迭代可迭代对象。当您可以将迭代器预先存储在变量中时:

const iter = range(5, 10);
for (var r of iter) {
  ...
}

不必要-for..of毕竟只需要对迭代器的单个引用。

您可以通过将对迭代器的单个引用传递到调用每个.next函数直到迭代器用尽的函数中,以在代码中进行模仿:

function *range(from, to) {
    var counter = from;
    while(to >= counter) {
        yield counter
        counter++
    }        
}

iterate(range(5, 10), num => {
  console.log(num);
});

function iterate(iterator, callback) {
  while (true) {
    const { value, done } = iterator.next();
    if (done) return;
    callback(value);
  }
}

如您所见,在将迭代器传递到iterate之前,无需将其存储在变量中,就像您可以将range(5, 10)调用直接用于for..of循环一样,因为循环(或函数)的内部为您完成了所有迭代。

答案 1 :(得分:1)

因此,对您的问题的简短回答是,for ... of loop实际上仅期望符合Iterable Protocol的对象。这是一个对象,具有绑定到返回可迭代对象的符号键Symbol.iterator的功能。

生成器实际上具有此属性 next函数(iterator protocol的实现需要此属性)。您可以在以下代码段中看到它。

const f = function*() {
  let i = -1; 
  while(true){
        i = i + 1; 
        yield i;
  }
};

const generator = f();
console.log(generator[Symbol.iterator]);
console.log(generator.next);

因此,这就是为什么您无需为for...of循环创建生成器对象的实例,也无需显式调用next的原因。由于Iterable协议的约定,这可以自动处理。

话虽如此,您可以通过以下方式从生成器对象创建迭代器对象(或直接调用for...of)来模仿while循环和next循环的行为:

const f = function*() {
  let i = -1; 
  while(true){
        i = i + 1; 
        yield i;
  }
};

const generator = f();
const iterator = generator[Symbol.iterator]();
    
let j = 0;
let next;
while(j < 5) {
      next = iterator.next();
      console.log('next: ', next);
      j = next.value;
}

原则上,这也可能是for...of循环的本机代码。