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]
,调用时返回不同的迭代器对象

因此,概括地说,您:

  • 调用返回iterable的方法
  • iterable是一个对象,它具有
    [Symbol.iterator]
    属性,并且可以访问原始对象的数据
  • 当调用该
    [Symbol.iterator]
    属性中的函数时,将得到一个迭代器对象
  • 迭代器对象包含一个
    .next()
    方法,该方法获取序列中的每个项,每次调用
    .next()
    时,它都会返回一个类似这样的对象
    {value:x,done:false}
  • 您可以跳过步骤1,让核心对象上有
    [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);
    }