Javascript中的迭代器和生成器

Iterator and a Generator in Javascript?

本文关键字:迭代器 Javascript      更新时间:2023-09-26

在Mozilla的页面迭代器和生成器上有一条语句:

虽然自定义迭代器是一个有用的工具,但创建它们需要由于需要显式维护内部状态。发电机提供了一种强大的替代方案:您可以通过编写单个函数来定义迭代算法其可以保持其自身的状态。

关于上面的解释,难道不可能在没有生成器的情况下编写一个迭代算法吗,比如:

Array[Symbol.iterator] = function(){
    return {
        next: function(){
            //logic
            return {
                value: "",
                done:false
            }
        }
    }
}

我无法理解。有人能解释一下他们创建替代方案的主要原因吗?对我来说似乎没有太大区别。

它们表面上看起来可能非常相似,但它们的使用方式却截然不同。

迭代程序和迭代程序

迭代器的定义相当严格:它们是包含next(可能还有其他一些)函数的对象(迭代器)。每次调用next函数时,都会返回一个具有两个属性的对象:

  • value:迭代器的当前值
  • done:迭代器完成了吗

另一方面,可迭代对象是具有Symbol.iterator关键字(表示众所周知的符号@@iterator)的属性的对象。该键包含一个函数,当调用该函数时,它将返回一个新的迭代器。一个可迭代的例子:

const list = {
    entries: { 0: 'a', 1: 'b' },
    [Symbol.iterator]: function(){
        let counter = 0;
        const entries = this.entries;
        return {
            next: function(){
                return {
                    value: entries[counter],
                    done: !entries.hasOwnProperty(counter++)
                }
            }
        }
    }
};

顾名思义,它们的主要目的是提供一个可以迭代的接口:

for (let item of list) { console.log(item); }
// 'a'
// 'b'

发电机

另一方面,发电机的用途要广泛得多。将它们视为可以暂停和恢复的功能会有所帮助。

虽然它们可以迭代(它们的迭代提供了next方法),但它们可以实现更复杂的过程,并通过next方法提供输入/输出通信。

一个简单的生成器:

function *mygen () {
   var myVal = yield 12;
   return myVal * 2;
}
const myIt = mygen();
const firstGenValue = myIt.next().value;
// Generator is paused and yields the first value
const result = myIt.next(firstGenValue * 2).value;
console.log(result); // 48

发电商授权

生成器可以委托给另一个生成器:

function *mydelgen(val) {
    yield val * 2;
}
function *mygen () {
    var myVal = yield 12;
    yield* mydelgen(myVal); // delegate to another generator
}
const myIt = mygen();
const val = myIt.next().value;
console.log(val);
console.log(myIt.next(val).value);
console.log(myIt.next().value);

发电机&承诺

Generators和Promises可以在co.等实用程序的帮助下一起创建一种自动异步迭代器

co(function *(){
  // resolve multiple promises in parallel
  var a = Promise.resolve(1);
  var b = Promise.resolve(2);
  var c = Promise.resolve(3);
  var res = yield [a, b, c];
  console.log(res);
  // => [1, 2, 3]
}).catch(onerror);

结论

因此,总之,可以说迭代器的主要目的是为要迭代的自定义对象创建一个接口,而生成器为同步和异步工作流提供了大量的可能性:

  • 有状态函数
  • 发电机委托
  • 发电机&承诺
  • CSP

等等。

难道不可能在没有生成器的情况下编写迭代算法吗。

不,不是。是的,可以将每个生成器算法编写为自定义迭代器,但代码中的// logic会复杂得多。该语句的重点是它不再是迭代的,而是递归的。

作为练习,这里有一个非常简单的迭代生成器函数:

function* traverseTree(node) {
    if (node == null) return;
    yield* traverseTree(node.left);
    yield node.value;
    yield* traverseTree(node.right);
}

尝试将其重写为自定义迭代器。无论你是陷入困境还是完成任务,它都会向你展示区别。