为什么生成器不支持map()?

时间:2015-07-05 16:19:02

标签: iterator generator ecmascript-6 map-function

对我来说,与数组非常相似的生成器应该支持非常基本的列表操作,例如map()filter()reduce(),这似乎是完全自然的。我错过了什么吗?

我编写了map的代码,看起来很简单,但是将所有函数嵌入到所有生成器中会更好:

let fancyGen = g => {
  let rv = function*() {
    for (let x of g) 
      yield x;
  }
  rv.map = function*(p) {
   for (let x of g) 
      yield p(x);
  } 
  return rv;
}

我是发电机的新手,所以欢迎对代码发表任何评论。特别是,这是编写“身份生成器”的最佳方式吗?

1 个答案:

答案 0 :(得分:3)

  

为什么生成器不支持map()?

因为它太容易填写为用户态实现。 ES3也不包括Array迭代方法,也许会在ES7中看到迭代器的变换器: - )

  

生成器,其功能与Arrays非常相似

不,请停止并区分迭代器生成器

  • 迭代器是一个符合迭代器协议的.next()方法的对象。
  • 生成器是由生成器函数(function*)创建的迭代器。它的.next()方法接受一个参数,该参数是生成器函数中每个yield的结果。它还有.return().throw()方法。

您最常对迭代器感兴趣,我们不会将值传递给next,也不关心最终结果 - 就像for of循环一样。我们可以轻松地使用所需的方法扩展它们:

var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
IteratorPrototype.map = function*(f) {
    for (var x of this)
        yield f(x);
};
IteratorPrototype.filter = function*(p) {
    for (var x of this)
        if (p(x))
            yield x;
};
IteratorPrototype.scan = function*(f, acc) {
    for (var x of this)
        yield acc = f(acc, x);
    return acc;
};
IteratorPrototype.reduce = function(f, acc) {
    for (var x of this)
        acc = f(acc, x);
    return acc;
};

这些应该足以满足开始和最常见的用例。一个合适的库会将它扩展到生成器,以便适​​当地传递值,并且还将处理迭代器在耗尽之前只能使用一次的问题(与数组相反)。