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