【问题标题】:I need a deep explanation of JavaScript Iterables. [closed]我需要深入解释 JavaScript Iterables。 [关闭]
【发布时间】:2018-02-23 09:56:48
【问题描述】:

我们为什么需要它们以及如何使用它们以及将 Iterable 功能添加到没有它的对象。这似乎是一个泛泛而谈的话题。

【问题讨论】:

  • 致关闭/关闭的选民,虽然这种材料在其他地方得到了很好的报道,但我无法在 SO 上找到它在这里被报道过的地方。如果您仍然认为值得关闭/否决,那是您的权利,但由于这不是骗局而且(在我看来)不是太宽泛,我回答了。
  • 我完全同意。这个问题肯定没有在 SO 的任何地方得到详细回答,因此导致我提出了合理的问题。

标签: javascript


【解决方案1】:

JavaScript 迭代器使用众所周知的符号 Symbol.iterator 来定义一个函数,该函数在调用时会返回一个对象。该对象有一个方法next,它返回另一个具有两个属性的对象:value(迭代器的当前值)和done(迭代器是否完成)。示例:

const foo = {};
foo[Symbol.iterator] = function* () {
  let i = 0;
  yield ++i;
};

let iter = foo[Symbol.iterator]();
iter.next(); // { value: 1, done: false }
iter.next(); // { value: 2, done: false }

注意* 表示generator function

迭代器也可以与for..of 等自动构造一起使用。然而,我在上面定义的那个不适用于for..of,因为它永远不会完成:循环遍历它的所有属性最终会导致内存不足。所以让我们使用一个数组:

const bar = [1,2];
for (let baz of bar) console.log(baz); // logs 1, 2, stops

所有内置集合(除了弱集合)都可以通过这种方式迭代,因为它们实现了这个接口。

如果调用者在它们被耗尽之前完成了对它们的处理,则可能会显式关闭保留像文件句柄之类的资源的可迭代对象。例如,我们将使用带有readFromFilegetNextLine 函数的假设文件API:

const fileReader = {
  [Symbol.iterator] (path) {
    return {
      fileHandle: readFromFile(path),
      next () {
        return {
          value: this.fileHandle.getNextLine(),
          done: false
        }
      }

      return () {
        this.fileHandle.close();
      }
    }
  }
};

您可以调用return 方法来防止泄漏文件句柄。请参阅 Reg Braithwaite 的this post 了解更多信息。另请注意,由于我们明确定义了方法返回的迭代器,因此我们不需要将其设为生成器函数。

如果您的迭代器是生成器函数,如我上面的无限计数列表中的那样,您可以通过yield 关键字pass it values

foo[Symbol.iterator] = function* () {
  let i = 0;
  let reset = yield ++i;
  if (reset) i = 0;
};

iter = foo[Symbol.iterator]();
iter.next().value;    // 1
iter.next().value     // 2
iter.next(true).value // 1 again

假设您有一些对象myObject,您希望能够迭代其属性。对于下一个示例,我们将忽略 Object.entries

const myObject = {
  a: 1,
  b: 2
};

Object.defineProperty(myObject, Symbol.iterator, {
  value: function* () {
    for (let key in myObject) {
      if (myObject.hasOwnProperty(key)) {
        yield [key, myObject[key]];
      }
    }
  }
});

iter = myObject[Symbol.iterator]();
iter.next(); // { value: ['a', 1], done: false }
iter.next(); // { value: ['b', 2], done: false }
iter.next(); // { value: undefined, done: true }

注意

在 ES 2015 之前,不保证对象属性有顺序。如果您在最新的 Chrome/FF/Safari 中运行上述代码,则一切正常,但如果您将其转换为旧版浏览器,您可能会首先看到 ['b', 2] 输出,或者不会在每次迭代时更改。

现在您对 JavaScript 可迭代对象的了解可能比您真正想要的要多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多