代码之家  ›  专栏  ›  技术社区  ›  Sammy I.

生成器是否同时返回迭代器和iterable?

  •  2
  • Sammy I.  · 技术社区  · 6 年前

    this question I asked before 我知道了 for...of 期望iterable,它是

    实现 @@iterable 方法,这意味着对象(或其原型链上的一个对象)必须具有具有 @@iterator 通过常量提供的密钥 Symbol.iterator

    所以,iterable看起来像这样:

    const iterableObject: {
      [Symbol.iterator]: function someIteratorFunction() {
        //...
      }
    }
    

    另一方面,我们有发电机,看起来像这样:

    function* generatorFoo(){
      yield 1;
      yield 2;
      yield 3;
      yield 4;
    }
    

    可用于 为了…… 结构如下:

    for(const item of generatorFoo())
      console.log(item);
    

    所以,呼唤 generatorFoo() 返回iterable自 为了…… 处理起来没问题。我也可以打电话 generatorFoo()[Symbol.iterator]() 并接收一个迭代器来确认这一点。

    但是,打电话 generatorFoo 也会返回迭代器,因为我可以调用 GeneratorFoo() 我用一种方法得到一个物体 next 要获取迭代器的下一个值,如下所示:

    const iteratorFromGen = generatorFoo();
    iteratorFromGen.next().value; //1
    iteratorFromGen.next().value; //2
    iteratorFromGen.next().value; //3
    iteratorFromGen.next().value; //4
    

    这是否意味着调用生成器函数返回一个可以访问 下一个 方法 [Symbol.iterator] 方法?

    当调用一个生成器函数时,我们是否得到一个既是迭代器又是iterable的对象?这是怎么做到的?

    1 回复  |  直到 6 年前
        1
  •  2
  •   CRice    6 年前

    简而言之,是的,生成器既是iterable又是iterator。

    From MDN :

    生成器对象由生成器函数返回,并且 符合iterable协议和迭代器协议。

    通过调用 Symbol.iterator 返回的生成器对象的方法与生成器对象本身相同。例如:

    function* gen() {
      let i = 0;
      while (i < 10) yield i++;
    }
    
    const iterableIterator = gen();
    console.log(iterableIterator === iterableIterator[Symbol.iterator]()); // true

    甚至可以通过遵照迭代器协议轻松复制该模式,并拥有一个 symbol.迭代器 返回的方法 this . 例如:

    class MyIterableIterator {
      
      constructor(arr) {
        this.arr = arr;
        this.i = 0;
      }
    
      [Symbol.iterator]() {
        return this;
      }
      
      next() {
        if (this.i === this.arr.length) return {done: true}
        return {value: this.arr[this.i++], done: false}
      }
    }
    
    const iterableIterator = new MyIterableIterator([1, 2, 3, 4, 5]);
    console.log(iterableIterator === iterableIterator[Symbol.iterator]()); // true
    
    // Works fine if you call next manually, or using a for-of loop.
    console.log(iterableIterator.next())
    for (let item of iterableIterator) {
      console.log(item);
    }