JavaScript/ES6:如何从一个类返回多个迭代器?
作为编程练习的一部分,我正在实现一个双链接列表,我希望允许开发人员使用JavaScript/ES6:如何从一个类返回多个迭代器?,javascript,ecmascript-6,iterator,Javascript,Ecmascript 6,Iterator,作为编程练习的一部分,我正在实现一个双链接列表,我希望允许开发人员使用for…in符号向前和向后迭代其节点 最基本的数据结构如下所示: class DoublyLinkedList { constructor(data) { if (data) { this.head = new DoublyLinkedListNode(data) } else { this.head = null }
for…in
符号向前和向后迭代其节点
最基本的数据结构如下所示:
class DoublyLinkedList {
constructor(data) {
if (data) {
this.head = new DoublyLinkedListNode(data)
} else {
this.head = null
}
}
append = (data) => {
if (!this.head) {
this.prepend(data)
} else {
const newTail = new DoublyLinkedListNode(data)
let current = this.head
while(current.next) {
current = current.next
}
current.next = newTail
newTail.prev = current
}
}
}
接下来,我添加了生成器函数:
*values() {
let current = this.head
while (current) {
yield current.data;
current = current.next;
}
}
*valuesBackward() {
let currentForwards = this.head
while (currentForwards.next) {
currentForwards = currentForwards.next
}
const tail = currentForwards
let currentBackwards = tail
while (currentBackwards) {
yield currentBackwards.data
currentBackwards = currentBackwards.prev
}
}
我可以在类中添加单个正向迭代器,并添加以下内容:
[Symbol.iterator]() { return this.values()}
iterateForward = () => [Symbol.iterator] = () => this.valuesBackward()
iterateBackward = () => [Symbol.iterator] = () => this.valuesBackward()
我尝试将以下两项添加到类中:
[Symbol.iterator]() { return this.values()}
iterateForward = () => [Symbol.iterator] = () => this.valuesBackward()
iterateBackward = () => [Symbol.iterator] = () => this.valuesBackward()
然后尝试对(list.iterateForward()中的节点)使用进行迭代
,但失败,出现错误TypeError:undefined不是函数
我想看看代码是有道理的,所以接下来我试着:
iterateForward = () => {
const vals = this.values()
const it = {
[Symbol.iterator]() {
return vals()
}
}
return it
}
这没有错误,但是迭代没有工作-迭代器运行了零次
我错过了什么?有可能实现我想要的吗?这些东西经常让我困惑,所以这里有一个总结,我们都可以参考 以下是背景信息
iterable
是一个具有[Symbol.iterator]
属性的对象,当您将该属性作为函数调用时,它将返回一个迭代器对象
迭代器对象有一个属性.next()
,每次调用该函数时,它都返回具有预期属性{value:x,done:false}
的对象。迭代器对象通常会在这个单独的对象中保持迭代的状态(因此迭代器可以彼此独立)
因此,为了支持多个迭代器,您需要创建多个方法,其中每个方法都返回一个不同的iterable对象,每个方法都有自己的[Symbol.iterator]
,调用时返回不同的迭代器对象
因此,概括地说,您:
[Symbol.iterator]
属性,并且可以访问原始对象的数据[Symbol.iterator]
属性中的函数时,将得到一个迭代器对象.next()
方法,该方法获取序列中的每个项,每次调用.next()
时,它都会返回一个类似这样的对象{value:x,done:false}
[Symbol.iterator]
属性。这实际上成为了您的默认迭代。如果您这样做:
for (let x of myObj) {
console.log(x);
}
它将访问myObj[Symbol.iterator]()
以获取迭代器。但是,如果您希望有多种方法来迭代集合,那么您可以创建单独的函数,每个函数都返回自己的iterable(它们自己的对象上有自己的[Symbol.iterator]
属性)
在一个数组中,您有
.entries()
和.values()
作为两个方法的示例,这两个方法返回不同的iterables,构成不同的迭代器
let x = ['a', 'b', 'c'];
for (let v of x.values()) {
console.log(v);
}
这将产生以下输出:
'a'
'b'
'c'
或者,对于.entries()
:
因此,.values()
和.entries()
中的每一个都返回一个不同的对象,每个对象都有一个不同的[Symbol.iterator]
,当作为函数调用时,它们会为其唯一序列返回一个不同的迭代器函数
对于数组,.values()
返回一个函数,当调用该函数时,该函数提供与直接迭代数组完全相同的迭代器(例如,数组本身的[Symbol.iterator]
属性)
现在,针对您的具体情况
您需要创建两个方法,例如.forward()
和.backward()
,每个方法都使用[Symbol.iterator]
属性创建一个对象,该属性是调用时返回其唯一迭代器对象的函数
因此,obj.forward()
将返回一个具有[Symbol.iterator]
属性的对象,该属性是一个函数,当调用该函数时,该函数将返回具有适当.next()
属性的迭代器对象,以向前迭代并返回适当的开始状态
因此,obj.backward()
将返回一个具有[Symbol.iterator]
属性的对象,该属性是一个函数,当调用该函数时,该函数将返回具有适当.next()
属性的迭代器对象以进行反向迭代并返回适当的开始状态
下面是一个使用数组的示例:
类myArray扩展了数组{
前进(){
返回此;//核心对象已具有适当的转发
//[Symbol.iterator]属性,因此我们可以使用它
}
向后(){
返回{
[符号.迭代器]:()=>{
设i=this.length-1;//在闭包中维护状态
返回{
下一步:()=>{//获取迭代中的下一项
if(i<0){
返回{done:true};
}否则{
返回{value:this[i--],done:false};
}
}
}
}
}
}
}
设x=newmyarray('a','b','c');
log(“使用默认迭代器转发”)
for(设v/x){
控制台日志(v);
}
console.log(“\n使用.forward()”)
for(设v/x.forward()){
控制台日志(v);
}
console.log(“\n使用.backward()”)
for(设v/x.backward()){
控制台日志(v);
}