JavaScript迭代器技术需求:将生成器项分发至子迭代器并扩展功能
Great question! Let’s break down how to build this flat, chainable iterator system in JavaScript—mirroring the readability of array map chaining while handling generator item distribution and routing. Here’s a practical, step-by-step approach:
1. Base Chainable Iterator Wrapper
First, we’ll create a foundational wrapper that mimics array method chaining. This gives us a starting point to extend with distribution logic:
class ChainableIterator { constructor(iterator) { this.iterator = iterator; } // Core chainable method (like array.map) to transform values map(transformFn) { return new ChainableIterator({ next: () => { const result = this.iterator.next(); if (!result.done) { return { value: transformFn(result.value), done: false }; } return result; } }); } // Helper to convert iterator output to an array for testing toArray() { const output = []; let result; while (!(result = this.iterator.next()).done) { output.push(result.value); } return output; } }
2. Distribute Items to Multiple Sub-Iterators
Next, we’ll extend the base class to support sending generator items to multiple sub-iterators, then collect their processed results for the next chain link:
class DistributableIterator extends ChainableIterator { distribute(subIterators) { return new ChainableIterator({ next: () => { const result = this.iterator.next(); if (result.done) return result; // Pass the current value to all sub-iterators and filter valid results const processedValues = subIterators .map(iterator => { const subResult = iterator.next(result.value); return subResult.done ? null : subResult.value; }) .filter(val => val !== null); return { value: processedValues, done: false }; } }); } }
3. Add Routing Logic for Targeted Distribution
To add control over which sub-iterator gets each item, we’ll modify the distribute method to accept a routing function. This function decides exactly where each value is sent:
class RoutingDistributableIterator extends ChainableIterator { distribute(subIterators, routeFn) { return new ChainableIterator({ next: () => { const result = this.iterator.next(); if (result.done) return result; const value = result.value; // Use the route function to get the target sub-iterator index const targetIndex = routeFn(value); // Handle invalid routes (adjust this logic to your needs) if (targetIndex < 0 || targetIndex >= subIterators.length) { return { value: "Route invalid", done: false }; } // Pass the value only to the selected sub-iterator const subResult = subIterators[targetIndex].next(value); return { value: subResult.done ? "Sub-iterator exhausted" : subResult.value, done: false }; } }); } }
Example Usage
Let’s put this all together with a sample generator and sub-iterators:
// Sample generator producing numbers function* numberGenerator() { yield 1; yield 2; yield 3; yield 4; } // Sub-iterators to process values const evenDoubler = { next: (val) => ({ value: val % 2 === 0 ? val * 2 : null, done: false }) }; const oddTripler = { next: (val) => ({ value: val % 2 !== 0 ? val * 3 : null, done: false }) }; // Route function: send even numbers to index 0, odds to index 1 const routeFn = (val) => val % 2 === 0 ? 0 : 1; // Build the chain const iterator = new RoutingDistributableIterator(numberGenerator()) .distribute([evenDoubler, oddTripler], routeFn) .map(val => val ?? "No match"); // Test the output console.log(iterator.toArray()); // Output: [3, 4, 9, 8]
Key Takeaways
- This structure keeps your code flat and readable, just like array method chaining—no nested loops or callbacks.
- Sub-iterators can be any iterator-compliant object (generators, objects with a
nextmethod, etc.). - The routing function gives you full flexibility to route items based on value, type, or custom business logic.
内容的提问来源于stack exchange,提问作者Erik

