[Javascript] Generator with example - 1
Difference between yield
and return
return
set done
to 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'
]
*/