2

If there's any problem with my iterator class I'd love to know.

class Group {
  constructor(arr = []){
    this.array = arr;
  }
  add(number) {
    this.array.push(number);
  }
  delete(number){
    this.array = this.array.filter(n => n != number);
  }
  has(number){
    return this.array.includes(number);
  }  
  static from(array){
    return new this(array);
  }
}

class GroupIterator{
    constrctor(group){
        this.x = 0;
        this.group = group;
    }
  next() {
    if (this.x == this.group.array.length) return {done: true};
    var val = this.x
    this.x++;
    return {val, done: false};
}

The problem is with the following call:

for(let value of Group.from(["a", "b", "c"])) {
  console.log(value);
}
// → a
// → b
// → c
vinzee
  • 10,965
  • 9
  • 34
  • 51
paula.em.lafon
  • 389
  • 3
  • 11
  • 1
    `next()` is missing a closing curly-bracket. Perhaps related: https://stackoverflow.com/questions/28739745/how-to-make-an-iterator-out-of-an-es6-class – Jeppe Feb 01 '19 at 20:42
  • It should probably throw an error saying `group is not iterable` since `Group.from` returns a `Group` object – adiga Feb 01 '19 at 20:43

1 Answers1

4

Because you're calling Group.from to create a Group, you need Group to have a generator that allows for iteration, else you'll get an error that it isn't iterable. Add

*[Symbol.iterator]() {
  for (const item of this.array) {
    yield item;
  }
}

as a method to Group (not to GroupIterator):

class Group {
  constructor(arr = []){
    this.array = arr;
  }
  *[Symbol.iterator]() {
    for (const item of this.array) {
      yield item;
    }
  }
  add(number) {
    this.array.push(number);
  }
  delete(number){
    this.array = this.array.filter(n => n != number);
  }
  has(number){
    return this.array.includes(number);
  }  
  static from(array){
    return new this(array);
  }
}
for(let value of Group.from(["a", "b", "c"])) {
  console.log(value);
}
// → a
// → b
// → c

Another option, to avoid double for..of wrapping, would be to call and return the array's Symbol.iterator:

[Symbol.iterator]() {
  return this.array[Symbol.iterator]();
}

class Group {
  constructor(arr = []){
    this.array = arr;
  }
  [Symbol.iterator]() {
    return this.array[Symbol.iterator]();
  }
  add(number) {
    this.array.push(number);
  }
  delete(number){
    this.array = this.array.filter(n => n != number);
  }
  has(number){
    return this.array.includes(number);
  }  
  static from(array){
    return new this(array);
  }
}
for(let value of Group.from(["a", "b", "c"])) {
  console.log(value);
}
// → a
// → b
// → c
CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
  • and this would be yielded to the Group class? I've never ever seen that form of implementation - can you please explain `[Symbol.iterator]()` a bit more - or explain why this makes the array iterable while it wasn't before? – messerbill Feb 01 '19 at 20:51
  • `this[Symbol.iterator] = function* () { yield "" }` is this a valid syntax? – adiga Feb 01 '19 at 20:51
  • 2
    @messerbill `for..of` will look up the `Symbol.iterator` property on the object and call it. In this case, since it's a generator function, everything `yield`ed will be an `item` in the loop. (Another option is to have `Symbol.iterator` *return* an object with a `next` method, somewhat similar to what you're trying to do in `GroupIterator`, but it's a lot more verbose and error-prone) Look up https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators – CertainPerformance Feb 01 '19 at 20:56