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



我试着在谷歌上搜索这个并查找类似的问题,但我似乎遗漏了一些基本的

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属性?

您需要调用[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());

实际上有两种不同的协议

  • "可读"-这是我使用*[Symbol.iterator]()生成器实现的。这允许。。。循环等

  • "Terator"-意思是在对象上定义下一个方法

引用文档:

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

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());

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

最新更新