在ES2015类中使用generator作为迭代器

时间:2017-07-24 18:57:11

标签: javascript ecmascript-6 es6-class

Please find the complete code example in action here.

我尝试将生成器用作迭代器,并将其与for..of中的toString循环结合使用,但不知怎的,它无效。

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

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

我有什么遗失的吗?

3 个答案:

答案 0 :(得分:0)

你有几个大问题

  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列表中的第一项,并且从不费心处理剩余的项目。

  5. 所以最后,我可能会写出你想要做的事情

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

答案 1 :(得分:0)

  

我认为在这个引用中使用for..of循环应该调用迭代器,但它不会。

确实如此。你刚才从未在你的例子中调用过该方法。

  

使用默认toString代替

将对象打印到控制台

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

  

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

没有。 toStringObject.prototype继承时,Symbol.toStringTag用作标准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]" 方法,请实际执行

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

SELECT sum(spend) AS spend 
FROM   sales_fact 
WHERE  person_id IN 
(
  SELECT person_id 
  FROM   enrollment_fact 
  WHERE  program = 'blah'
  GROUP  BY person_id
)

答案 2 :(得分:0)

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