How can I write a generator in a JavaScript class?

后端 未结 3 475
囚心锁ツ
囚心锁ツ 2020-12-28 13:04

Usually, I write code like this:

//definition
exports.getReply = function * (msg){
    //...
    return reply; 
}
//usage
var msg = yield getReply (\'hello\'         


        
相关标签:
3条回答
  • 2020-12-28 13:16

    Edit: Add more examples.
    Your class definition is (almost) correct.The error was in instantiation var Reply = new Reply();. This tries to redefine variable assigned to class name. Also generator function is expected to yield something. I elaborated a little OP code to show working example.

    class Reply {
      //added for test purpose
      constructor(...args) {
        this.args = args;
      }
      * getReply(msg) {
          for (let arg in this.args) {
            let reply = msg + this.args[arg];
            //generator should yield something
            yield reply;
          }
          //next call returns (yields) {done:true,value:undefined}
      }
      * otherFun() {
          yield this.getReply('Nice to meet you '); //yields Generator object
          yield this.getReply('See you '); //Yes, this can access 
          //next call yields {done:true, value:undefined}
      }
      * evenMore() {
          yield* this.getReply('I miss you '); //yields generator result(s)
          yield* this.getReply('I miss you even more ');
      }
    }
    //now test what we have
    const reply = new Reply('Peter', 'James', 'John');
    //let and var here are interchangeable because of Global scope
    var r = reply.getReply('Hello ');
    var msg = r.next(); //{done:false,value:"..."}
    while (!msg.done) {
      console.log(msg.value);
      msg = r.next();
    }
    var other = reply.otherFun();
    var o = other.next(); //{done:false,value:Generator}
    while (!o.done) {
      let gen = o.value;
      msg = gen.next();
      while (!msg.done) {
        console.log(msg.value);
        msg = gen.next();
      }
      o = other.next();
    }
    var more = reply.evenMore();
    msg = more.next();
    while (!msg.done) {
      console.log(msg.value);
      msg = more.next();
    }
    //update of 1/12/2019
    //more examples
    for (let r of reply.getReply('for ')) {
      console.log(r);
    }
    for (let r of reply.evenMore()) {
      console.log(r);
    }
    //note that the following doesn't work because of lack of star (*) inside the generator function
    for (let r of reply.otherFun()) {
      console.log(r);
    }

    UPDATE 1/12/2019

    As suggested by @BugBuddy for..of loop looks even nicer (But doesn't work in all cases). See updated lines in the snippet.

    0 讨论(0)
  • 2020-12-28 13:36

    Generators are functions with a .next() for getting the yield'ed values or you can yield a generator function to let it know it doesn't need to "wait" upon encountering a yield statement for a .next to be called (reply.getReply().next(fn))

    Your second piece of code is almost correct:

    class Reply{
        *getReply (msg){
            //...
            return reply; 
        }
         *otherFun(){
            this.getReply();  //`this` seem to have no access to `getReply`
        }
    }
    var Reply = new Reply();
    Reply.getReply();   //out of class,how can I get access to `getReply`?
    

    First of all, please use const or let when working in ES6 and only use the uppercase variant for classes. You are trying to overwrite the class Reply statement with the var Reply = statement, which is not possible since the Identifier 'Reply' is already declared.

    The answer you are looking for is as followed:
    Just like you are doing in the first example, you should yield the generator functions, so your could should look like this:

    class Reply{
        *getReply (msg){
            // yield something here, otherwise you should use a normal function
            return reply;
        }
         *otherFun(){
            const reply = yield this.getReply();  // yield the generator so it does what it needs to and doesn't wait for the .next() to be called on it
            return `${reply} within class ${this.constructor.name}`;
        }
    }
    const reply = new Reply();
    const answer = yield reply.getReply('foo'); 
    // getReply is a generator function, so it needs a `yield` or `.next()` to run beyond the first `yield` in the function
    
    0 讨论(0)
  • 2020-12-28 13:37

    TL; DR for confused visitors from Google:

    In Javascript, how do I write a generator function in a class?

    class A {
        * values() {
            yield "a value";
            yield* [1, 2, 3, 4, 5];
        }
    }
    

    is syntactically correct. It works. You’re welcome and now dismissed.

    0 讨论(0)
提交回复
热议问题