【问题标题】:Using generator as an iterator in an ES2015 class在 ES2015 类中使用生成器作为迭代器
【发布时间】:2017-07-24 18:57:10
【问题描述】:

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 打印对象。

我有什么遗漏吗?

【问题讨论】:

  • Symbol.toStringTagtoString 不同。你想达到什么目的?
  • 我正在尝试提供toString 实现。我认为这些与Mozilla doc 声明它是由Object.prototype.toString() 方法在内部调用的相同。即使我将其更改为普通的 toString 我也会得到相同的行为。我希望得到1 -> 2 -> 3 之类的列表表示形式。

标签: javascript ecmascript-6 es6-class


【解决方案1】:

你有几个大问题

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

    [Symbol.toStringTag]() {
    

    应该是

    get [Symbol.toStringTag]() {
    

    因此该属性是一个 getter,将在访问时返回一个字符串。

  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;
}

【讨论】:

    【解决方案2】:

    我想使用 for..of 循环和这个引用应该调用迭代器,但它没有。

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

    使用默认的toString 将对象打印到控制台

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

    toString方法如下图-[Symbol.toStringTag]() { …

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

    如果你想实现一个自定义的toString 方法,实际实现那个

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

    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]"
    

    【讨论】:

    • 我刚刚意识到虽然上面的解决方案确实有效并且是一种方法,但它实际上并没有使用迭代器。您可以简单地删除 *[Symbol.iterator]() 实现,它仍然有效。实际上,正如@loganfsmyth 所提到的,我原来的 toString 很蹩脚。我将在下面发布工作版本。感谢您的回答,因为我对 toStringSymbol.toStringTag 有了很多了解,它把我推向了正确的方向。
    • @OmkarPatil 要使用迭代器,您可以执行类似return `{ ${Array.from(this).join(" -> ")} -> null}`
    【解决方案3】:

    感谢@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());
    

    【讨论】:

      猜你喜欢
      • 2020-03-10
      • 2018-05-16
      • 2016-07-01
      • 1970-01-01
      • 2017-02-21
      • 2014-02-02
      • 2018-11-01
      • 1970-01-01
      • 2021-10-29
      相关资源
      最近更新 更多