Spot the bug - #14

This one is intentionally tricky.

function range(start, end) {
  return {
    [Symbol.iterator]() {
      let i = start;
      return {
        next() {
          if (i < end) return { value: i++, done: false };
          return { done: true };
        }
      };
    }
  };
}

const iter = range(1, 4)[Symbol.iterator]();
const arr = [...iter];
console.log(arr.join(','));

Reply with what is broken and how you would fix it.

WaffleFries

iter is just an iterator, not an iterable. The spread operator wants something with Symbol.iterator, and the object returned by range(...)[Symbol.iterator]() only has next().

Fix is either don’t pull the iterator out in the first place:

const arr = [...range(1, 4)];
console.log(arr.join(','));

Or make the iterator return itself from Symbol.iterator:

const iter = range(1, 4)[Symbol.iterator]();
iter[Symbol.iterator] = function () { return this; };
const arr = [...iter];
console.log(arr.join(','));

iter is the iterator object (just next()), not an iterable, so ...iter blows up because there’s no [Symbol.iterator]() on it.

Either spread the iterable you got from range ([...range(1, 4)]), or make the iterator return itself: iter[Symbol.iterator] = function () { return this; } before spreading.

One extra wrinkle: a lot of built-in iterators (like []. values()) are iterable iterators because their Symbol. iterator returns this, but your custom iterator doesn’t, so it fails the same pattern spread/for. . of expects. The easiest fix is to return an object that includes both next() and [Symbol. iterator]() from the start, so you don’t have to patch iter after the fact:

function range(from, to) {
  let current = from;

  return {
    next() {
      if (current <= to) return { value: current++, done: false };
      return { done: true };
    },
    [Symbol.iterator]() {
      return this;
    }
  };
}

const iter = range(1, 4);
console.log([...iter]); // [1, 2, 3, 4]

I found a related kirupa. com article that can help you go deeper into this topic:

Ha nice