如何将简单迭代器转换为JavaScript Generator?
嘿,我懂Generator刚上手的时候确实有点摸不着头脑,不过你的这个场景完全适合用Generator来重构,而且代码会简洁很多!
先说说你原来的代码里的小问题:每次调用keyIterator()都会返回一个新的迭代器对象,但这些迭代器共享了同一个iteratorCount状态,导致它们的next()调用会互相干扰——比如如果你创建两个迭代器实例,调用其中一个的next()会影响另一个的结果,这可不是迭代器该有的行为哦。
用Generator重写的话,我们可以轻松实现状态独立的迭代器,而且不用手动写next()方法、管理计数器,代码可读性拉满:
class KeyGen { constructor(numOfKeys) { this.numOfKeys = numOfKeys; } // 用Generator语法定义迭代器方法,*是关键标记 *keyIterator() { // 循环生成0到numOfKeys-1的序列 for (let index = 0; index < this.numOfKeys; index++) { yield index; } } } // 测试一下 const keyGen = new KeyGen(4); const iterator = keyGen.keyIterator(); // 先拿到一个独立的迭代器实例 console.log(iterator.next()); // { value: 0, done: false } console.log(iterator.next()); // { value: 1, done: false } console.log(iterator.next()); // { value: 2, done: false } console.log(iterator.next()); // { value: 3, done: false } console.log(iterator.next()); // { value: undefined, done: true }
这个版本里,每次调用keyIterator()都会生成一个全新的Generator迭代器,每个迭代器都有自己的循环状态,互相不会干扰。比如你可以同时创建两个迭代器,它们各自独立输出序列:
const iter1 = keyGen.keyIterator(); const iter2 = keyGen.keyIterator(); console.log(iter1.next().value); // 0 console.log(iter2.next().value); // 0 console.log(iter1.next().value); // 1 console.log(iter2.next().value); // 1
如果你的需求就是要保持原来那种共享计数器的行为(虽然不太推荐,不符合迭代器设计规范),也可以用Generator实现,只需要把计数器放在类实例上:
class KeyGen { constructor(numOfKeys) { this.keys = new Array(numOfKeys).fill(0).map((_, index) => index); this.iteratorCount = 0; } *keyIterator() { while (this.iteratorCount < this.keys.length) { yield this.keys[this.iteratorCount++]; } } } // 测试和你原来代码一致的行为 const keyGen = new KeyGen(4); console.log(keyGen.keyIterator().next().value); // 0 console.log(keyGen.keyIterator().next().value); // 1 console.log(keyGen.keyIterator().next().value); // 2 console.log(keyGen.keyIterator().next().value); // 3
总的来说,Generator就是为这类自定义迭代器场景设计的,你的需求完全适用,放心用就好!
内容的提问来源于stack exchange,提问作者John Abraham
相关产品推荐
相关产品推荐

