Learn Js with Ut

Generators in Js

August 07, 2020

Generators in Js 😍

Generators are iterable. That provide more clean and easy way to work with iterable.

Before we go towards the generators first we recap what we have studied in our last blog about the iterables.

Let’s see One example to recap iterable:

//first we create a simple object.
let iterableObj = {
  from: 1,
  to: 3,
}

// Now to make it iterable we have to define [Symbol.iterator]()
// as a method in iterableObj.
iterableObj[Symbol.iterator] = function () {
  // This function will return an iterator object{}
  //Over which for...of loop will start its iteration.
  return {
    // This is iterator object which is used by
    //for..of loop.
    // this iterator object have next() method
    //i.e call by for..of loop to get
    // the next value
    current: this.from,
    last: this.to,
    //whenever for..of wants new value, it calls next()
    next() {
      if (this.current <= this.last) {
        return { done: false, value: this.current++ };
      } else {
        return { done: true };
      }
    },
  };
}

// now see result...
for (let key of iteratorObj) {
  console.log(key) // 1,2,3
}

I hope above example is helpful to recap about the iterables.

Now we use generators in above example

let iterableObj = {
  from: 1,
  to: 3,

  *[Symbol.iterator](){ // This is the generator function
    for(let current = this.from; current <= this.to; current++)
      {
          yield current;
      }
  }
}

for(let value of iterableObj){
  console.log(value); // 1 2 3
}

It’s too clean by using the generator.

Now let me explain what is happening?

If you are a old school guy you probably now about the pointers.

Syntax:

 int *ptr = 123;
 // or
 int* func(){
  return 0;
 }

Same that we define generators in js

Syntax

function* nameOfTheFunction(){}

Putting the * in front of the function to make generator function.

Normal function vs Generator function

Normal function

  • Syntax function nameOfTheFunction(){}.
  • Normal function always return only single value nothing else.
  • Whenever we call the function it always start executing from begining of the function body till the end of the function body or return statement.

Generator function

  • Syntax function* nameOfTheFunction(){}.
  • Generators can return multiple values,one after another on demand.
  • whenever we call the generators by using the .next() method then it start executing until the nearest yield yield. Then again when we call the generator second time its start it’s execution from the previous yield and execute till the nearest yield.And this process going on until the return or end of the function.

Let’s see some example:

// Generator function
function* gen(){ // <-- right now code execution not started yet

  yield 1;
  yield 2;
  return 3;

}

const generatorObj = gen();
// on calling generator function it will return the generator object
console.log(generatorObj); // [object generator]

The function execution has not started yet.

Main method of a generatorObj is next(). When we call next() then function execution runs until the nearest yield.And so on

// Generator function
function* gen(){

  yield 1; // <-- now execution stops at nearest yield on first next call
  yield 2; // <-- The execution stops here on second next call.
  return 3;// <-- The execution stops and ends after third next call

}

const generator = gen();
// on calling generator function it will return the generator object
console.log(generator); // [object generator]
let result = generator.next();
let result1 = generator.next();
let result2 = generator.next();

console.log(result); // {value:1,done:false}
console.log(result1); // {value:2,done:false}
console.log(result2); // {value:3,done:true}

Now the generator is done. Because it return done:true. so now on calling generator.next() it will return same object {value:3,done:true};

I think this is too much about the Generator intro. If you want to know more please go here.

Usage of generators 👀

  1. Counter in generator:
function* counter(){
  let count = 1;
  while(true){
    yield count++;
  }
}

const counters = counter();

console.log(counters.next()); // {value:1,done:false}
console.log(counters.next()); // {value:2,done:false}
console.log(counters.next()); // {value:3,done:false}
console.log(counters.next().value); // 4
  1. Find # hashTag and @ in twitter comments:
let twitterComment = `There are many #libraries that
  build over the concept of #generators
  ex- #ReactSaga #co.js and many more
  @React @javascript`;
let regEx = new RegExp(/(#|@)(\w+)/,"g");

function* func(){

    let match = null;
    do{
        match = regEx.exec(twitterComment);
        if(match){
        yield match;

        }

    }while(match);

}

for(let tweets of func()){
  console.log(tweets);
  // logs
  // ["#libraries","#","libraries"]
  // ["#generators","#","generators"]
  // ["#ReactSaga","#","ReactSaga"]
  //["#co","#","co"]
  // ["@React","@","React"]
  // ["@javascript","@","javascript"]
}
  1. Passing values in generators:
function* findSum(a,b){
  let c = a + b; // a + b results store into c
  let d = yield c;// <--  function execution stops here on first next() call
  // Here d stores value that we pass into next()
  return c * d;// function execution start
  //again from previous yield
  // and completed into return statement
}
const sum = findSum(1,2); // This will return the generator obj

console.log(sum.next());
//===> logs {value:3,done:false}
// In first call of the next() we didn't pass value.
// if we pass value generators ignore it.
console.log(sum.next(3));
// ==> logs {value:9,done:true}
//ON the second call of the next() we can pass arguments


Please subscribe our news letter

If you like what you just read. Please subscribe to our newsletter. So new content will be delivered to your inbox :)

Hii this is Utkarsh Srivastava. I live in India. I
Coding, Learning New Tech, and Playing PC Games. You can find me on
© 2020, Built with