在 ES2015 中使用生成器作为迭代器 class

Using generator as an iterator in an ES2015 class

Please find the complete code example in action here.

我正在尝试将生成器用作迭代器并将其与 toString 中的 for..of 循环结合使用,但不知何故它不起作用。

这是我的(生成器)迭代器的样子 -

*[Symbol.iterator]() {
    let temp = this.head;
    while (temp) {
        yield temp.item;
        temp = temp.next;
    }
}

然后我尝试在 toString 方法中使用它,如下所示 -

[Symbol.toStringTag]() {
    for (const temp of this) {
        return `${temp} -> `;
    }
}

我想象使用 for..of 循环和 this 引用应该调用迭代器,但它没有。这可以通过控制台日志中缺少 Iterator called 语句来观察,并且使用默认 toString 打印对象。

有什么我遗漏的吗?

你有几个大问题

  1. Symbol.toStringTag 应该是解析为字符串而不是函数的 属性。这意味着

    [Symbol.toStringTag]() {
    

    应该是

    get [Symbol.toStringTag]() {
    

    因此 属性 是一个 getter,它将 return 一个访问字符串。

  2. console.log(list)不调用.toString(),所以需要console.log(list.toString()).

  3. 您会注意到,list.toString() === "[object 1 -> ]"可能不是您想要的。 toStringTag 被附加到另一个字符串中,有点像

    `[object ${this[Symbol.toStringTag]}]`
    

    所以如果你真的想要一个漂亮的字符串输出,你可能只想要

    toString() {
    

    作为您的方法,跳过 toStringTag.

  4. 如果你试图序列化整个列表,你的循环就没有意义,因为你 return 是列表中的第一个项目,而从不费心处理其余的的项目。

所以最后,我可能会把你想做的写成

toString() {
  let result = "";
  for (let item = this.head; item; item = item.next) {
    if (result) result += ' -> ';
    result += item.item;
  }
  return result;
}

I would imagine that using for..of loop with this reference should call the iterator but it doesn't.

确实如此。您只是从未在示例中调用该方法。

the object is printed to console using default toString instead

它不是,它是使用控制台自己的对象表示打印的(在 babeljs.io repl 上,它似乎是 .constructor.nameJSON.stringify 的混合)。

toString method as shown below - [Symbol.toStringTag]() { …

没有。 Symbol.toStringTag 在被 Object.prototype 继承时用作标准 toString 表示的一部分。它不是一种方法,而是一个普通值(您可以使用 getter,但您不应该使用)。

如果要实现自定义 toString 方法,实际实现 that.

这是一个更新的示例,可以满足您的需求:

class SLListNode {
    constructor(item, next) {
        this.item = item;
        this.next = next;
    }
    toString() {
        return `${this.item} -> ${this.next}`;
    }
}

class SinglyLinkedList {
    constructor() {
        this.length = 0;
        this.head = null;
    }
    addFirst(item) {
        this.head = new SLListNode(item, this.head);
        this.length++;
    }
    *[Symbol.iterator]() {
        console.log('Iterator called');
        let temp = this.head;
        while (temp) {
            yield temp.item;
            temp = temp.next;
        }
    }
    getLength() {
        return this.length;
    }
    toString() {
        return `{ ${this.head.toString()} }`;
    }
}
SinglyLinkedList.prototype[Symbol.toStringTag] = "LinkedList";

const list = new SinglyLinkedList();
list.addFirst(3);
list.addFirst(2);
list.addFirst(1);
console.log(String(list)); // "{ 1 -> 2 -> 3 -> null }"
console.log(Object.prototype.toString.call(list)); // "[object LinkedList]"

感谢@bergi 和@loganfsmyth,他们的回答指出了我原始代码中的错误并将我推向了正确的方向,这里是有效的解决方案并将生成器用作迭代器 -

class SLListNode {
    constructor(item) {
        this.item = item;
    }
    toString() {
        return `${this.item}`;
    }
}
class SinglyLinkedList {
    constructor() {
        this.length = 0;
    }
    addFirst(item) {
        const newNode = new SLListNode(item);
        newNode.next = this.head;
        this.head = newNode;
        this.length++;
    }
    *[Symbol.iterator]() {
        let temp = this.head;
        while (temp) {
            yield temp.item;
            temp = temp.next;
        }
    }
    getLength() {
        return this.length;
    }
    toString() {
        let str = "";
        for (const temp of this) {
            str = `${str} -> ${temp}`;
        }
        return str;
    }
}
const list = new SinglyLinkedList();
list.addFirst(3);
list.addFirst(2);
list.addFirst(1);
console.log(list.toString());