【问题标题】:Cannot use next() on iterable object created using *[Symbol.iterator]() generator javascript无法在使用 *[Symbol.iterator]() 生成器 javascript 创建的可迭代对象上使用 next()
【发布时间】:2020-10-18 21:17:54
【问题描述】:

我试过用谷歌搜索这个并查看类似的问题,但我似乎遗漏了一些基本的东西

let collection = {
    items: [],
    *[Symbol.iterator]() {
        for (let item of this.items) {
            yield item;
        }
    }
}
collection.items.push(1);
collection.items.push(2);
console.log(collection.next()); 

这会引发错误

console.log(collection.next());
                       ^

TypeError: collection.next is not a function 

根据我的阅读,我应该能够在集合对象上使用 next(),因为这会调用 Symbol.iterator 属性?

【问题讨论】:

  • 不,.next() 在第一次调用返回的对象上。尝试在 for ... ofArray.from() 或类似的地方使用您的对象。
  • for (let i of collection) console.log(i); 返回我推入 items 数组属性的两个数字。所以这很好用,只是下一个方法不起作用。

标签: javascript generator next


【解决方案1】:

需要调用[Symbol.iterator]()方法得到一个迭代器对象,然后在返回的对象上调用next()方法:

let collection = {
  items: [],
  *[Symbol.iterator]() {
    for (let item of this.items) {
      yield item;
    }
  }
};

collection.items.push(1);
collection.items.push(2);

let iterator = collection[Symbol.iterator]();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

请记住,数组本身已经实现了可迭代协议,实际上您通过使用for...of 循环在[Symbol.iterator]() 定义中使用了该协议,因此collection 对象在这里并不是必需的:

let items = [];

items.push(1);
items.push(2);

let iterator = items[Symbol.iterator]();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

【讨论】:

  • 我知道“数组”已经是任何可迭代的。我试图创建一个新的集合对象,它具有可以自定义的奇异属性。这可能是相当神秘的。但是我想我的想法是,一个新的可迭代对象可能不应该以单例样式创建 next 方法,而是应该每次都创建一个迭代器,这样我们就可以同时运行多个迭代器。
  • @lindsaymacvean 是的。如果您的迭代器对象引用自己以便方便地用作可迭代对象,那么同一个对象应该实现两者的唯一时间,例如let iterator = { [Symbol.iterator]() { return this; }, next() { /* some non-trivial implementation */ } };
【解决方案2】:

实际上有两种不同的协议

  • 'Iterable' - 这是我使用*[Symbol.iterator]() 生成器实现的。这允许 for...of 循环等。

  • 'Iterator' - 表示在对象上定义下一个方法。

引用文档:

创建一个同时满足迭代器和可迭代协议的对象很容易(如下例所示)。 这样做允许迭代器被期望迭代的各种语法消耗。因此,如果不实现 Iterable,实现 Iterator Protocol 很少有用。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

所以我重写了我的代码:

let collection = {
    items: [],
    *[Symbol.iterator]() {
        for (let item of this.items) {
            yield item;
        }
    },
    i: 0,
    next: function() {
        let done = (this.i >= this.items.length);
        let value = !done ? this.items[this.i++] : undefined
        return {
            done,
            value
        }
    }
}
collection.items.push(1);
collection.items.push(2);
for (let i of collection) console.log(i); // demonstrates the iterable protocol
console.log(collection.next()); // demonstrates the iterator protocol
console.log(collection.next());
console.log(collection.next());

最后一点,这不是私有对象,应该包装在类中或立即调用的函数中,以避免任何其他代码等访问这些属性。

【讨论】:

    猜你喜欢
    • 2023-03-20
    • 2021-10-21
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 2017-12-18
    • 2018-11-25
    • 2022-01-19
    • 2020-03-31
    相关资源
    最近更新 更多