无法在使用 *[Symbol.iterator]() 生成器 javascript 创建的可迭代对象上使用 next()

Posted

技术标签:

【中文标题】无法在使用 *[Symbol.iterator]() 生成器 javascript 创建的可迭代对象上使用 next()【英文标题】:Cannot use next() on iterable object created using *[Symbol.iterator]() generator javascript 【发布时间】: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 数组属性的两个数字。所以这很好用,只是下一个方法不起作用。 【参考方案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());

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

【讨论】:

以上是关于无法在使用 *[Symbol.iterator]() 生成器 javascript 创建的可迭代对象上使用 next()的主要内容,如果未能解决你的问题,请参考以下文章

我想在useEffect react Js中使用带有foreach的axios,但它给了我(无法读取属性Symbol(Symbol.iterator)错误?

更新状态 |对象不可迭代(无法读取属性 Symbol(Symbol.iterator))

无法读取未定义(递归函数)的属性“符号(Symbol.iterator)”

ECMA Script 6_symbol(symbol.iterator) 新接口_iterator接口

Es6 Symbol.iterator

arr[Symbol.iterator] 不是使用带有上下文的 useState 的函数