可迭代:带有迭代器或生成器的对象 [英] Iterables: Objects with iterators, or generators

查看:87
本文介绍了可迭代:带有迭代器或生成器的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们假设使用已定义的迭代器对对象进行两种类似的实现:一种使用生成器的迭代器,另一个使用 iterables 。这两个都可以与 Array.from 一起使用,并且它们都可以迭代。这两种方法有什么区别,首选哪一种,为什么?

Let's assume two similar implementations of an object with a defined iterator: one iterator using generators, the other using iterables. Both of these two work with Array.from, and both of them can be iterated over. What are the differences in these two approaches, which one is preferred, and why? Is there ever a need for the lesser approach?

class Foo {
  constructor( ...args ) {
    this.f = args;
  }
  [Symbol.iterator]() {
    let c = 0;

    const i = {

      next: () => {
        if ( c < this.f.length ) {
          return {value:this.f[c++], done: false};
        }
        else {
          return {value:undefined,done:true};
        }
      }

    };
    return i;
  }

};

class Bar {
  constructor( ...args ) {
    this.f = args;
  }
  *[Symbol.iterator]() {
    let c = 0;

    if ( c < this.f.length ) {
      yield this.f[c++];
    }
    else {
      return;
    }
  }

};

在这里,我们可以对它们进行测试以表明它们基本相同。

Here we can test them both to show that they're essentially the same.

var o1 = new Foo([1,2,3]);
for ( let x of o1 ) {
  console.warn(x)
}
console.log(o1, Array.from(o1));

var o2 = new Bar([1,2,3]);
for ( let x of o2 ) {
  console.warn(x)
}
console.log(o2, Array.from(o2));


推荐答案


两个类似的实现一个具有已定义迭代器的对象:一个迭代器使用生成器,另一个迭代器使用可迭代器。

two similar implementations of an object with a defined iterator: one iterator using generators, the other using iterables.

首先让我们正确定义术语:您已经定义了两个(构造函数)是 Iterables 的对象。从它们具有 Symbol.iterator 方法的意义上来说,它们都是可迭代的,该方法返回 iterator -具有的对象next 方法。其中一种方法是通过按字面值返回一个对象来实现的,另一种方法是使用生成器语法来实现的。

Let's correct the terminology first: You have defined two (constructors for) objects that are Iterables. They are both iterable in the sense that they have have Symbol.iterator method that returns an iterator - an object with a next method. One of these methods is implemented by literally returning an object, the other is implemented using generator syntax.


我们可以对其进行测试以表明它们基本上是相同的。

We can test them both to show that they're essentially the same.

嗯,不,您犯了一个本质性的错误:您在自己的代码中使用了rest参数构造函数,因此两个对象最终都以一个数组作为其 f 值结束。

Uh, no, you've made an essential mistake: you've used rest parameters in your constructors, so both of your objects ended up with an array of one array as their f value.

如果使用 var o = new FooBar(1、2、3) constructor(args){就是您所期望的,示例将表明它们绝对不会做同样的事情。

If you used either var o = new FooBar(1, 2, 3) or constructor(args) {, the property would be what you expected and the examples would show that they absolutely don't do the same thing.

因此,让我们修复代码:

So let's fix your code:

class Test {
  constructor(arr) {
    this.f = arr;
  }
}
class Foo extends Test {
  [Symbol.iterator]() {
    let c = 0;
    return {
      next: () => {
        if ( c < this.f.length ) {
          return {value: this.f[c++], done: false};
        } else {
          return {value: undefined, done: true};
        }
      }
    };
  }
}
class Bar extends Test {
  *[Symbol.iterator]() {
    let c = 0;
    while (c < this.f.length) // written a lot nicer using a `for` loop
      yield this.f[c++];
    // return undefined; // we really should omit that
  }
}

for (let test of [Foo, Bar]) {
  console.log(test.name);
  const o = new test([1,2,3]);
  for (const x of o)
    console.log(x)
  console.log(Array.from(o));
}

现在可以完成您真正想要的操作。

This now does what you actually wanted.


这两者有什么区别

What are the differences in these two approaches?

我希望可以从上面的代码中清楚地看到:生成器函数要简单得多。

I hope it's clear from the above code: generator functions are much simpler.


首选哪一个,为什么?

Which one is preferred, and why?

猜测一下:-)语法Sugar通过抽象提高了可读性并简化了复杂的行为。

Make a guess :-) Syntactic sugar improves readability and simplifies complex behaviours through abstraction.


是否需要使用较小的方法?

Is there ever a need for the lesser approach?

我无法想象任何标准的用例。当然,生成器语法是引擎需要支持的功能,但是完整的迭代协议也是如此。也许在某些极端情况下,手工制作的微优化迭代器对象比生成器更快/更便宜/更轻,例如对于恒定的无限迭代器,但我对此表示怀疑。

I can't imagine any standard use case. Of course generator syntax is a feature that needs to be supported by the engine, but so is the complete iteration protocol. Maybe there are some edge cases where a hand-crafted micro-optimised iterator object is faster/cheaper/lighter than a generator, e.g. for constant infinite iterators, but I doubt it.

这篇关于可迭代:带有迭代器或生成器的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆