Overriding Built-in Iterables

Consumers look up [Symbol.iterator] at run time, so you can replace it on one object. A primitive string cannot hold properties, so wrap it with new String(). The method takes no arguments and must return a fresh iterator; keep the position in a closure.

Replacing the iterator of one String objectJavaScriptLive
const s = new String('hello');                  // a String object can own properties
s[Symbol.iterator] = function () {
  let i = -1;                                   // position lives in a closure
  return { next: () => ({ value: 'abc'[++i], done: i > 2 }) };
};
console.log([...s], String(s), [...'hello'].length);

Only iteration changed; conversion and other strings are untouched. Never patch Array.prototype[Symbol.iterator]: every spread and for...of on the page, library code included, would change, and V8 86,723 abandons its fast path for spreading arrays.