Javascript Iterables:具有迭代器或生成器的对象

Javascript Iterables:具有迭代器或生成器的对象,javascript,ecmascript-6,generator,iterable,Javascript,Ecmascript 6,Generator,Iterable,让我们假设一个对象有两个类似的实现:一个迭代器使用,另一个使用。这两个函数都与数组一起工作。从,这两个函数都可以被迭代。这两种方法的区别是什么?首选哪种方法?为什么?是否有必要采用较小的方法 class Foo { constructor( ...args ) { this.f = args; } [Symbol.iterator]() { let c = 0; const i = { next: () => { if (

让我们假设一个对象有两个类似的实现:一个迭代器使用,另一个使用。这两个函数都与数组一起工作。从,这两个函数都可以被迭代。这两种方法的区别是什么?首选哪种方法?为什么?是否有必要采用较小的方法

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;
    }
  }

};
使用已定义迭代器的对象的两个类似实现:一个迭代器使用生成器,另一个使用iterables

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

我们可以对它们进行测试,以证明它们本质上是一样的

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));
不,你犯了一个根本性的错误:你在构造函数中使用了rest参数,所以你的两个对象都以一个数组的数组作为它们的
f

如果使用
var o=new FooBar(1,2,3)
constructor(args){
,则该属性将是您所期望的,并且示例将显示它们绝对不会做相同的事情

因此,让我们修复您的代码:

类测试{
建造师(arr){
这个。f=arr;
}
}
类Foo扩展测试{
[符号.迭代器](){
设c=0;
返回{
下一个:()=>{
如果(c<此f.长度){
返回{value:this.f[c++],done:false};
}否则{
返回{value:undefined,done:true};
}
}
};
}
}
类栏扩展测试{
*[符号.迭代器](){
设c=0;
而(c
使用已定义迭代器的对象的两个类似实现:一个迭代器使用生成器,另一个使用iterables

让我们首先更正术语:您已经定义了两个(的构造函数)对象。它们都是iterable,因为它们具有返回迭代器的
Symbol.iterator
方法-具有
next
方法的对象。其中一个方法通过逐字返回对象来实现,另一个方法使用生成器语法来实现

我们可以对它们进行测试,以证明它们本质上是一样的

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));
不,你犯了一个根本性的错误:你在构造函数中使用了rest参数,所以你的两个对象都以一个数组的数组作为它们的
f

如果使用
var o=new FooBar(1,2,3)
constructor(args){
,则该属性将是您所期望的,并且示例将显示它们绝对不会做相同的事情

因此,让我们修复您的代码:

类测试{
建造师(arr){
这个。f=arr;
}
}
类Foo扩展测试{
[符号.迭代器](){
设c=0;
返回{
下一个:()=>{
如果(c<此f.长度){
返回{value:this.f[c++],done:false};
}否则{
返回{value:undefined,done:true};
}
}
};
}
}
类栏扩展测试{
*[符号.迭代器](){
设c=0;
而(c}
对我来说,生成器只是创建迭代器的语法糖。当然,代码越复杂,它就是一个非常强大的语法糖,因为你不必自己维护迭代器状态。就个人而言,我总是更喜欢生成器,因为样板较少。对我来说,生成器只是创建I的语法糖畸胎体。当然,代码越复杂,它是一种非常强大的语法糖分,因为你不必自己维护迭代器状态。就个人而言,我总是喜欢使用生成器,因为样板文件较少。我已经澄清了标题。你能进一步回答,与生成器相比,使用迭代器的对象是否更好?我无法想象任何真实世界的用例。当然,当语法不受支持时,生成器就不存在了,但在这种情况下,所有其他ES6功能也不存在了。也许在某些边缘情况下,手工制作的迭代器对象比生成器更快/更便宜/更轻/更好,例如,对于常量无限迭代器。如果更新ans那么,我将把它标记为选中。这涵盖了我想学习的所有内容。我已经澄清了标题。你能进一步回答一下,是否有更好的方法使用对象和迭代器,而不是生成器吗?我无法想象现实世界中的任何用例。当然,生成器在语法不受支持的情况下是不可用的,但在这种情况下,所有其他ES6都不支持功能也不会。也许在某些边缘情况下,手工制作的迭代器对象比生成器更快/更便宜/更轻/更好,例如常数无限迭代器。如果你用它更新答案,我会将其标记为选中。这涵盖了我想学的所有内容。