在 ES6 中,有 iterator.next();有什么办法可以提供 iterator.previous() 吗?

In ES6, there is iterator.next(); is there any way to supply iterator.previous()?

完成完整的 ES6 Compatibility table。刚上 Set().

const set = new Set();
set.add('foo');
set.add('baz');

const iterator = set.values();
iterator.next(); // { value: "foo", done: false }
iterator.next(); // { value: "baz", done: false }

是否可以编写类似于 iterator.next() 的方法,但它是向后迭代而不是向前迭代(即 iterator.previous())?

恐怕没有 JS 方法可以做到这一点,但是没有人会阻止您将以前的值保存在变量中并从中读取。

values() returns 一个迭代器对象,不可能向后迭代它们,因为 JavaScript 迭代器对象可能是无限的。例如,考虑这个

function * Counter() {
    "use strict";
    var i = 0;
    while (1) {
        yield i++;
    }
}

现在,您可以使用 Counter() 创建一个永不结束的迭代器。因此,通常情况下,迭代器不支持倒退。


如果您非常需要像 backIterator 这样的东西,那么您必须维护迭代器产生的值,然后根据 next 调用来回移动。

虽然此时你不能向迭代器提供一个类似于next()方法的previous()方法,但其他答案都不正确。您可以通过更改迭代器的 next() 方法,使用 ES iteration protocol 向后迭代任何可迭代对象。

真正的罪魁祸首是您需要决定是否要向前迭代向后迭代。目前,您不能同时执行这两项操作,因为您必须覆盖迭代器中的 next() 方法才能使其向后工作。

继续使用 Set 对象的示例,您可以覆盖 values() 方法并提供您自己的可迭代迭代器,如下所示:

const set = new Set();
set.add('foo');
set.add('baz');

const iterator = set.values();
console.log(iterator.next()); // { value: "foo", done: false }
console.log(iterator.next()); // { value: "baz", done: false }

set.values = function () {
  const reversedContents = Array.from(this);
  return {
    [Symbol.iterator]() {
      return this;
    },
    next() {
      const isDone = reversedContents.length === 0;
      return {
        value: reversedContents.pop(),
        done: isDone
      };
    }
  };
}

const reverseIterator = set.values();
console.log(reverseIterator.next()); // { value: "baz", done: false }
console.log(reverseIterator.next()); // { value: "foo", done: false }

这并不理想,因为这会从集合中创建一个数组,以便从集合中获取最后一个元素。

没有什么可以阻止你这样做,例如下面通过包装 Set.

您显然不能直接迭代 previous(),但您可以手动调用它,或者通过调用 previous() 简单地切换方向,next 现在反向迭代。

values() {
  const items = [...set.values()];
  let index = -1;

  return {
    [Symbol.iterator]() {
      return this;
    },

    next() {
      var item = items[index + 1];
      if (item) {
        return {
          value: item,
          done: false
        };
      }
      return { done: true };
    },

    previous() {
      var item = items[index - 1];
      if (item) {
        return {
          value: item,
          done: false
        };
      }
      return { done: true };
    }
  };
}