[Javascript] Generator with example - 1

发布时间 2023-05-25 17:43:45作者: Zhentiw

Difference between yieldand return

returnset doneto true

/**
 * Example 1
 */

function* loggerator() {
  console.log("running");
  yield "paused";
  console.log("running again");
  return "stopped";
}

let logger = loggerator();
console.log(logger.next()); // running
// { value: 'paused', done: false }
console.log(logger.next()); // running again
// { value: 'stopped', done: true }

 

Generator are both iterable and iterators

/**
 * Example 2
 */

// generators are both iterable and iterators

function* abc() {
  yield "a";
  yield "b";
  yield "c";
}

for (let letter of abc()) {
  console.log(letter);
}

console.log([...abc()]);

 

Custom iterables with @@iterator

/**
 * Example 3
 */

// custom iterables with @@iterator

const cardDeck = {
  suits: ["♥", "♠", "♣", "♦"],
  court: ["J", "Q", "K", "A"],
  [Symbol.iterator]: function* () {
    for (let suit of this.suits) {
      for (let i = 2; i <= 10; i++) {
        yield `${suit} ${i}`;
      }
      for (let c of this.court) {
        yield `${suit} ${c}`;
      }
    }
  },
};

console.log([...cardDeck]);
/**
 * [
  '♥ 2', '♥ 3', '♥ 4',  '♥ 5',  '♥ 6',  '♥ 7',
  '♥ 8', '♥ 9', '♥ 10', '♥ J',  '♥ Q',  '♥ K',
  '♥ A', '♠ 2', '♠ 3',  '♠ 4',  '♠ 5',  '♠ 6',
  '♠ 7', '♠ 8', '♠ 9',  '♠ 10', '♠ J',  '♠ Q',
  '♠ K', '♠ A', '♣ 2',  '♣ 3',  '♣ 4',  '♣ 5',
  '♣ 6', '♣ 7', '♣ 8',  '♣ 9',  '♣ 10', '♣ J',
  '♣ Q', '♣ K', '♣ A',  '♦ 2',  '♦ 3',  '♦ 4',
  '♦ 5', '♦ 6', '♦ 7',  '♦ 8',  '♦ 9',  '♦ 10',
  '♦ J', '♦ Q', '♦ K',  '♦ A'
]
 */

Another way to write it:

const cardDeck = {
  suits: ["♥", "♠", "♣", "♦"],
  court: ["J", "Q", "K", "A"],
  *[Symbol.iterator]() {
    for (let suit of this.suits) {
      for (let i = 2; i <= 10; i++) {
        yield `${suit} ${i}`;
      }
      for (let c of this.court) {
        yield `${suit} ${c}`;
      }
    }
  },
};

 

Lazy evaluation & infinite sequences

/**
 * Example 4
 */

// lazy evaluation & infinite sequences

function* infiniteAndBeyond() {
  let i = 1;
  while (true) {
    yield i++;
  }
}

function* take(n, iterable) {
  for (let item of iterable) {
    if (n <= 0) return;
    n--;
    yield item;
  }
}

console.log([...take(5, infiniteAndBeyond())]); //[1, 2, 3, 4, 5];

function* map(iterable, mapFn) {
  for (let item of iterable) {
    yield mapFn(item);
  }
}
const inc = (num) => num + 1;
console.log([...map(take(5, infiniteAndBeyond()), inc)]); // [ 2, 3, 4, 5, 6 ]

 

yield*:delegate iteration control to another iterator

/**
 * Example 5
 */

function binaryTreeNode(value) {
  const node = { value };
  node[Symbol.iterator] = function* depthFirst() {
    yield node.value;
    if (node.leftChild) {
      // explainer: yield* is a special syntax that allows us to delegate iteration control to another iterator
      yield* node.leftChild;
    }
    if (node.rightChild) {
      yield* node.rightChild;
    }
  };
  return node;
}

const makeTree = () => {
  const root = binaryTreeNode("root");
  root.leftChild = binaryTreeNode("branch left");
  root.rightChild = binaryTreeNode("branch right");
  root.leftChild.leftChild = binaryTreeNode("leaf L1");
  root.leftChild.rightChild = binaryTreeNode("leaf L2");
  root.rightChild.leftChild = binaryTreeNode("leaf R1");
  return root;
};
const tree = makeTree();

console.log([...tree]);
/**
 * [
  'root',
  'branch left',
  'leaf L1',
  'leaf L2',
  'branch right',
  'leaf R1'
]
 */