class NumberRange {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
for (let i = this.start; i <= this.end; i++) {
yield i;
}
}
}
const range = new NumberRange(1, 5);
const iter = range[Symbol.iterator]; // extracted β no object
const standalone = iter.bind(range); // attempting to bind
// Calling as method works:
console.log([...range].join(', '));
// But this fails:
try {
iter(); // called without 'range' as this
} catch(e) {
console.log(e.constructor.name);
}class NumberRange {
constructor(start, end) {
this.start = start;
this.end = end;
}
*[Symbol.iterator]() {
// Capture this in the outer scope for safety
const { start, end } = this;
for (let i = start; i <= end; i++) {
yield i;
}
}
}
// β
Correct usage: iterate through the object, not the extracted method
const range = new NumberRange(1, 5);
console.log([...range].join(', ')); // 1, 2, 3, 4, 5
// If you need to pass the iterator around:
const boundIter = range[Symbol.iterator].bind(range);
// or: () => range[Symbol.iterator]()Bug: Generator methods lose "this" when extracted. iter() is called without the range object, so this.start and this.end are undefined.
Explanation: Generator methods have the same "this" rules as regular methods. Destructuring {start, end} from this early makes the generator body independent of this binding.
Key Insight: Generator methods lose "this" when extracted from their object. Destructure needed properties at the start of the generator to avoid this dependency.